refactor(miniprotocols): Use pure functions for state machines (#84)
This commit is contained in:
parent
90ad1e9217
commit
dc422284b2
20 changed files with 446 additions and 531 deletions
|
|
@ -1,13 +1,8 @@
|
|||
use core::panic;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pallas_codec::minicbor::{decode, encode, Decode, Encode, Encoder};
|
||||
use pallas_codec::minicbor::{decode, encode, Decode, Decoder, Encode, Encoder};
|
||||
|
||||
use crate::machines::{Agent, MachineOutput};
|
||||
|
||||
use super::common::{RefuseReason, VersionNumber};
|
||||
|
||||
pub type VersionTable = super::common::VersionTable<VersionData>;
|
||||
pub type VersionTable = super::protocol::VersionTable<VersionData>;
|
||||
|
||||
const PROTOCOL_V4: u64 = 4;
|
||||
const PROTOCOL_V5: u64 = 5;
|
||||
|
|
@ -66,9 +61,7 @@ impl Encode for VersionData {
|
|||
}
|
||||
|
||||
impl<'b> Decode<'b> for VersionData {
|
||||
fn decode(
|
||||
d: &mut pallas_codec::minicbor::Decoder<'b>,
|
||||
) -> Result<Self, pallas_codec::minicbor::decode::Error> {
|
||||
fn decode(d: &mut Decoder<'b>) -> Result<Self, decode::Error> {
|
||||
d.array()?;
|
||||
let network_magic = d.u64()?;
|
||||
let initiator_and_responder_diffusion_mode = d.bool()?;
|
||||
|
|
@ -79,133 +72,3 @@ impl<'b> Decode<'b> for VersionData {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Message {
|
||||
Propose(VersionTable),
|
||||
Accept(VersionNumber, VersionData),
|
||||
Refuse(RefuseReason),
|
||||
}
|
||||
|
||||
impl Encode for Message {
|
||||
fn encode<W: encode::Write>(&self, e: &mut Encoder<W>) -> Result<(), encode::Error<W::Error>> {
|
||||
match self {
|
||||
Message::Propose(version_table) => {
|
||||
e.array(2)?.u16(0)?;
|
||||
version_table.encode(e)?;
|
||||
}
|
||||
Message::Accept(version_number, version_data) => {
|
||||
e.array(3)?.u16(1)?;
|
||||
e.u64(*version_number)?;
|
||||
version_data.encode(e)?;
|
||||
}
|
||||
Message::Refuse(reason) => {
|
||||
e.array(2)?.u16(2)?;
|
||||
reason.encode(e)?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Decode<'b> for Message {
|
||||
fn decode(
|
||||
d: &mut pallas_codec::minicbor::Decoder<'b>,
|
||||
) -> Result<Self, pallas_codec::minicbor::decode::Error> {
|
||||
d.array()?;
|
||||
|
||||
match d.u16()? {
|
||||
0 => todo!(),
|
||||
1 => {
|
||||
let version_number = d.u64()?;
|
||||
let version_data = VersionData::decode(d)?;
|
||||
Ok(Message::Accept(version_number, version_data))
|
||||
}
|
||||
2 => {
|
||||
let reason = RefuseReason::decode(d)?;
|
||||
Ok(Message::Refuse(reason))
|
||||
}
|
||||
_ => Err(decode::Error::message(
|
||||
"unknown variant for handshake message",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
Propose,
|
||||
Confirm,
|
||||
Done,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Output {
|
||||
Pending,
|
||||
Accepted(VersionNumber, VersionData),
|
||||
Refused(RefuseReason),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
pub state: State,
|
||||
pub output: Output,
|
||||
pub version_table: VersionTable,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn initial(version_table: VersionTable) -> Self {
|
||||
Client {
|
||||
state: State::Propose,
|
||||
output: Output::Pending,
|
||||
version_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Agent for Client {
|
||||
type Message = Message;
|
||||
|
||||
fn is_done(&self) -> bool {
|
||||
self.state == State::Done
|
||||
}
|
||||
|
||||
fn has_agency(&self) -> bool {
|
||||
match self.state {
|
||||
State::Propose => true,
|
||||
State::Confirm => false,
|
||||
State::Done => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn send_next(self, tx: &impl MachineOutput) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
match self.state {
|
||||
State::Propose => {
|
||||
tx.send_msg(&Message::Propose(self.version_table.clone()))?;
|
||||
|
||||
Ok(Self {
|
||||
state: State::Confirm,
|
||||
..self
|
||||
})
|
||||
}
|
||||
_ => panic!("I don't have agency, nothing to send"),
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_next(self, msg: Self::Message) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
match (self.state, msg) {
|
||||
(State::Confirm, Message::Accept(version, data)) => Ok(Self {
|
||||
state: State::Done,
|
||||
output: Output::Accepted(version, data),
|
||||
..self
|
||||
}),
|
||||
(State::Confirm, Message::Refuse(reason)) => Ok(Self {
|
||||
state: State::Done,
|
||||
output: Output::Refused(reason),
|
||||
..self
|
||||
}),
|
||||
_ => panic!("Current state does't expect to receive a message"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue