diff --git a/Code/consensus/src/executor.rs b/Code/consensus/src/executor.rs index 029dd77c4..58a6e3c5b 100644 --- a/Code/consensus/src/executor.rs +++ b/Code/consensus/src/executor.rs @@ -27,20 +27,6 @@ where TimeoutElapsed(Timeout), } -#[derive(Clone, Debug)] -pub struct Executor -where - Ctx: Context, -{ - height: Ctx::Height, - private_key: Secret>, - address: Ctx::Address, - validator_set: Ctx::ValidatorSet, - pub round: Round, - votes: VoteKeeper, - round_states: BTreeMap>, -} - #[derive(Clone, Debug, PartialEq, Eq)] pub enum Message where @@ -53,11 +39,37 @@ where NewRound(Round), } -impl Executor +pub trait Client +where + Ctx: Context, +{ + fn get_value(&self) -> Ctx::Value; + fn validate_proposal(&self, proposal: &Ctx::Proposal) -> bool; +} + +#[derive(Clone, Debug)] +pub struct Executor where Ctx: Context, + Client: self::Client, +{ + pub client: Client, + pub height: Ctx::Height, + pub private_key: Secret>, + pub address: Ctx::Address, + pub validator_set: Ctx::ValidatorSet, + pub round: Round, + pub votes: VoteKeeper, + pub round_states: BTreeMap>, +} + +impl Executor +where + Ctx: Context, + Client: self::Client, { pub fn new( + client: Client, height: Ctx::Height, validator_set: Ctx::ValidatorSet, private_key: PrivateKey, @@ -66,6 +78,7 @@ where let votes = VoteKeeper::new(validator_set.total_voting_power()); Self { + client, height, private_key: Secret::new(private_key), address, @@ -76,9 +89,12 @@ where } } - pub fn get_value(&self) -> Ctx::Value { - // TODO - add external interface to get the value - Ctx::DUMMY_VALUE + fn get_value(&self) -> Ctx::Value { + self.client.get_value() + } + + fn validate_proposal(&self, proposal: &Ctx::Proposal) -> bool { + self.client.validate_proposal(proposal) } pub fn execute(&mut self, msg: Event) -> Option> { @@ -143,7 +159,9 @@ where } fn apply_proposal(&mut self, proposal: Ctx::Proposal) -> Option> { - // TODO: Check for invalid proposal + if !self.validate_proposal(&proposal) { + todo!("invalid proposal"); + } // Check that there is an ongoing round let Some(round_state) = self.round_states.get(&self.round) else { diff --git a/Code/test/src/client.rs b/Code/test/src/client.rs new file mode 100644 index 000000000..4e05c2345 --- /dev/null +++ b/Code/test/src/client.rs @@ -0,0 +1,24 @@ +use malachite_consensus::executor::Client; + +use crate::{Proposal, TestContext, Value}; + +pub struct TestClient { + pub value: Value, + pub is_valid: fn(&Proposal) -> bool, +} + +impl TestClient { + pub fn new(value: Value, is_valid: fn(&Proposal) -> bool) -> Self { + Self { value, is_valid } + } +} + +impl Client for TestClient { + fn get_value(&self) -> Value { + self.value.clone() + } + + fn validate_proposal(&self, proposal: &Proposal) -> bool { + (self.is_valid)(proposal) + } +} diff --git a/Code/test/src/lib.rs b/Code/test/src/lib.rs index c39e1682a..fc979bccb 100644 --- a/Code/test/src/lib.rs +++ b/Code/test/src/lib.rs @@ -1,6 +1,7 @@ #![forbid(unsafe_code)] #![deny(trivial_casts, trivial_numeric_casts)] +mod client; mod context; mod height; mod proposal; @@ -9,6 +10,7 @@ mod validator_set; mod value; mod vote; +pub use crate::client::*; pub use crate::context::*; pub use crate::height::*; pub use crate::proposal::*; diff --git a/Code/test/tests/consensus_executor.rs b/Code/test/tests/consensus_executor.rs index b17cbca88..67d54afa9 100644 --- a/Code/test/tests/consensus_executor.rs +++ b/Code/test/tests/consensus_executor.rs @@ -3,7 +3,7 @@ use malachite_consensus::executor::{Event, Executor, Message}; use malachite_round::state::{RoundValue, State, Step}; use malachite_test::{ - Address, Height, PrivateKey, Proposal, TestContext, Validator, ValidatorSet, Vote, + Address, Height, PrivateKey, Proposal, TestClient, TestContext, Validator, ValidatorSet, Vote, }; use rand::rngs::StdRng; use rand::SeedableRng; @@ -47,8 +47,8 @@ fn executor_steps_proposer() { let (my_sk, my_addr) = (sk1, addr1); let vs = ValidatorSet::new(vec![v1, v2.clone(), v3.clone()]); - - let mut executor = Executor::new(Height::new(1), vs, my_sk.clone(), my_addr); + let client = TestClient::new(value.clone(), |_| true); + let mut executor = Executor::new(client, Height::new(1), vs, my_sk.clone(), my_addr); let proposal = Proposal::new(Height::new(1), Round::new(0), value.clone(), Round::new(-1)); @@ -229,7 +229,8 @@ fn executor_steps_not_proposer() { let (my_sk, my_addr) = (sk2, addr2); let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]); - let mut executor = Executor::new(Height::new(1), vs, my_sk.clone(), my_addr); + let client = TestClient::new(value.clone(), |_| true); + let mut executor = Executor::new(client, Height::new(1), vs, my_sk.clone(), my_addr); let proposal = Proposal::new(Height::new(1), Round::new(0), value.clone(), Round::new(-1)); @@ -410,7 +411,8 @@ fn executor_steps_not_proposer_timeout_multiple_rounds() { let (my_sk, my_addr) = (sk3, addr3); let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]); - let mut executor = Executor::new(Height::new(1), vs, my_sk.clone(), my_addr); + let client = TestClient::new(value.clone(), |_| true); + let mut executor = Executor::new(client, Height::new(1), vs, my_sk.clone(), my_addr); let steps = vec![ // Start round 0, we, v3, are not the proposer