Decode refuse reason in handshake

This commit is contained in:
Santiago Carmuega 2021-11-21 12:02:14 -03:00
parent c2d537b83f
commit c203f70693
3 changed files with 79 additions and 79 deletions

View file

@ -1,5 +1,5 @@
use itertools::Itertools; use itertools::Itertools;
use pallas_machines::{DecodePayload, EncodePayload, PayloadEncoder}; use pallas_machines::{DecodePayload, EncodePayload, MachineError, PayloadEncoder};
use std::{collections::HashMap, fmt::Debug}; use std::{collections::HashMap, fmt::Debug};
pub const TESTNET_MAGIC: u64 = 1097911063; pub const TESTNET_MAGIC: u64 = 1097911063;
@ -17,10 +17,7 @@ impl<T> EncodePayload for VersionTable<T>
where where
T: Debug + Clone + EncodePayload + DecodePayload, T: Debug + Clone + EncodePayload + DecodePayload,
{ {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
e.map(self.values.len() as u64)?; e.map(self.values.len() as u64)?;
for key in self.values.keys().sorted() { for key in self.values.keys().sorted() {
@ -44,10 +41,7 @@ pub enum RefuseReason {
} }
impl EncodePayload for RefuseReason { impl EncodePayload for RefuseReason {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
match self { match self {
RefuseReason::VersionMismatch(versions) => { RefuseReason::VersionMismatch(versions) => {
e.array(2)?; e.array(2)?;
@ -69,7 +63,7 @@ impl EncodePayload for RefuseReason {
} }
RefuseReason::Refused(version, msg) => { RefuseReason::Refused(version, msg) => {
e.array(3)?; e.array(3)?;
e.u16(1)?; e.u16(2)?;
e.u64(*version)?; e.u64(*version)?;
e.str(msg)?; e.str(msg)?;
@ -78,3 +72,32 @@ impl EncodePayload for RefuseReason {
} }
} }
} }
impl DecodePayload for RefuseReason {
fn decode_payload(
d: &mut pallas_machines::PayloadDecoder,
) -> Result<Self, Box<dyn std::error::Error>> {
d.array()?;
match d.u16()? {
0 => {
let versions = d.array_iter::<u64>()?;
let versions = versions.try_collect()?;
Ok(RefuseReason::VersionMismatch(versions))
}
1 => {
let version = d.u64()?;
let msg = d.str()?;
Ok(RefuseReason::HandshakeDecodeError(version, msg.to_string()))
}
2 => {
let version = d.u64()?;
let msg = d.str()?;
Ok(RefuseReason::Refused(version, msg.to_string()))
}
x => Err(Box::new(MachineError::BadLabel(x))),
}
}
}

View file

@ -1,9 +1,10 @@
use core::panic; use core::panic;
use std::collections::HashMap; use std::collections::HashMap;
use itertools::Merge;
use pallas_machines::{ use pallas_machines::{
Agent, DecodePayload, EncodePayload, MachineError, MachineOutput, Agent, DecodePayload, EncodePayload, MachineError, MachineOutput, PayloadDecoder,
PayloadDecoder, PayloadEncoder, PayloadEncoder,
}; };
use crate::common::{NetworkMagic, RefuseReason, VersionNumber}; use crate::common::{NetworkMagic, RefuseReason, VersionNumber};
@ -42,13 +43,10 @@ impl VersionTable {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VersionData (NetworkMagic,); pub struct VersionData(NetworkMagic);
impl EncodePayload for VersionData { impl EncodePayload for VersionData {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
e.u64(self.0)?; e.u64(self.0)?;
Ok(()) Ok(())
@ -56,9 +54,7 @@ impl EncodePayload for VersionData {
} }
impl DecodePayload for VersionData { impl DecodePayload for VersionData {
fn decode_payload( fn decode_payload(d: &mut PayloadDecoder) -> Result<Self, Box<dyn std::error::Error>> {
d: &mut PayloadDecoder,
) -> Result<Self, Box<dyn std::error::Error>> {
let network_magic = d.u64()?; let network_magic = d.u64()?;
Ok(Self(network_magic)) Ok(Self(network_magic))
@ -73,10 +69,7 @@ pub enum Message {
} }
impl EncodePayload for Message { impl EncodePayload for Message {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
match self { match self {
Message::Propose(version_table) => { Message::Propose(version_table) => {
e.array(2)?.u16(0)?; e.array(2)?.u16(0)?;
@ -98,24 +91,22 @@ impl EncodePayload for Message {
} }
impl DecodePayload for Message { impl DecodePayload for Message {
fn decode_payload( fn decode_payload(d: &mut PayloadDecoder) -> Result<Self, Box<dyn std::error::Error>> {
d: &mut PayloadDecoder,
) -> Result<Self, Box<dyn std::error::Error>> {
d.array()?; d.array()?;
let msg = match d.u16()? { match d.u16()? {
0 => todo!(), 0 => todo!(),
1 => { 1 => {
let version_number = d.u64()?; let version_number = d.u64()?;
let version_data = VersionData::decode_payload(d)?; let version_data = VersionData::decode_payload(d)?;
Ok(Message::Accept(version_number, version_data))
Message::Accept(version_number, version_data)
} }
2 => todo!(), 2 => {
x => return Err(Box::new(MachineError::BadLabel(x))), let reason = RefuseReason::decode_payload(d)?;
}; Ok(Message::Refuse(reason))
}
Ok(msg) x => Err(Box::new(MachineError::BadLabel(x))),
}
} }
} }
@ -165,10 +156,7 @@ impl Agent for Client {
} }
} }
fn send_next( fn send_next(self, tx: &impl MachineOutput) -> Result<Self, Box<dyn std::error::Error>> {
self,
tx: &impl MachineOutput,
) -> Result<Self, Box<dyn std::error::Error>> {
match self.state { match self.state {
State::Propose => { State::Propose => {
tx.send_msg(&Message::Propose(self.version_table.clone()))?; tx.send_msg(&Message::Propose(self.version_table.clone()))?;
@ -182,10 +170,7 @@ impl Agent for Client {
} }
} }
fn receive_next( fn receive_next(self, msg: Self::Message) -> Result<Self, Box<dyn std::error::Error>> {
self,
msg: Self::Message,
) -> Result<Self, Box<dyn std::error::Error>> {
match (self.state, msg) { match (self.state, msg) {
(State::Confirm, Message::Accept(version, data)) => Ok(Self { (State::Confirm, Message::Accept(version, data)) => Ok(Self {
state: State::Done, state: State::Done,

View file

@ -2,8 +2,8 @@ use core::panic;
use std::collections::HashMap; use std::collections::HashMap;
use pallas_machines::{ use pallas_machines::{
Agent, DecodePayload, EncodePayload, MachineError, MachineOutput, Agent, DecodePayload, EncodePayload, MachineError, MachineOutput, PayloadDecoder,
PayloadDecoder, PayloadEncoder, PayloadEncoder,
}; };
use crate::common::{RefuseReason, VersionNumber}; use crate::common::{RefuseReason, VersionNumber};
@ -28,6 +28,17 @@ impl VersionTable {
VersionTable { values } VersionTable { values }
} }
pub fn v6_and_above(network_magic: u64) -> VersionTable {
let values = vec![
(PROTOCOL_V6, VersionData::new(network_magic, false)),
(PROTOCOL_V7, VersionData::new(network_magic, false)),
]
.into_iter()
.collect::<HashMap<u64, VersionData>>();
VersionTable { values }
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -37,10 +48,7 @@ pub struct VersionData {
} }
impl VersionData { impl VersionData {
pub fn new( pub fn new(network_magic: u64, initiator_and_responder_diffusion_mode: bool) -> Self {
network_magic: u64,
initiator_and_responder_diffusion_mode: bool,
) -> Self {
VersionData { VersionData {
network_magic, network_magic,
initiator_and_responder_diffusion_mode, initiator_and_responder_diffusion_mode,
@ -49,10 +57,7 @@ impl VersionData {
} }
impl EncodePayload for VersionData { impl EncodePayload for VersionData {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
e.array(2)? e.array(2)?
.u64(self.network_magic)? .u64(self.network_magic)?
.bool(self.initiator_and_responder_diffusion_mode)?; .bool(self.initiator_and_responder_diffusion_mode)?;
@ -62,9 +67,7 @@ impl EncodePayload for VersionData {
} }
impl DecodePayload for VersionData { impl DecodePayload for VersionData {
fn decode_payload( fn decode_payload(d: &mut PayloadDecoder) -> Result<Self, Box<dyn std::error::Error>> {
d: &mut PayloadDecoder,
) -> Result<Self, Box<dyn std::error::Error>> {
d.array()?; d.array()?;
let network_magic = d.u64()?; let network_magic = d.u64()?;
let initiator_and_responder_diffusion_mode = d.bool()?; let initiator_and_responder_diffusion_mode = d.bool()?;
@ -84,10 +87,7 @@ pub enum Message {
} }
impl EncodePayload for Message { impl EncodePayload for Message {
fn encode_payload( fn encode_payload(&self, e: &mut PayloadEncoder) -> Result<(), Box<dyn std::error::Error>> {
&self,
e: &mut PayloadEncoder,
) -> Result<(), Box<dyn std::error::Error>> {
match self { match self {
Message::Propose(version_table) => { Message::Propose(version_table) => {
e.array(2)?.u16(0)?; e.array(2)?.u16(0)?;
@ -109,24 +109,22 @@ impl EncodePayload for Message {
} }
impl DecodePayload for Message { impl DecodePayload for Message {
fn decode_payload( fn decode_payload(d: &mut PayloadDecoder) -> Result<Self, Box<dyn std::error::Error>> {
d: &mut PayloadDecoder,
) -> Result<Self, Box<dyn std::error::Error>> {
d.array()?; d.array()?;
let msg = match d.u16()? { match d.u16()? {
0 => todo!(), 0 => todo!(),
1 => { 1 => {
let version_number = d.u64()?; let version_number = d.u64()?;
let version_data = VersionData::decode_payload(d)?; let version_data = VersionData::decode_payload(d)?;
Ok(Message::Accept(version_number, version_data))
Message::Accept(version_number, version_data)
} }
2 => todo!(), 2 => {
x => return Err(Box::new(MachineError::BadLabel(x))), let reason = RefuseReason::decode_payload(d)?;
}; Ok(Message::Refuse(reason))
}
Ok(msg) x => Err(Box::new(MachineError::BadLabel(x))),
}
} }
} }
@ -176,10 +174,7 @@ impl Agent for Client {
} }
} }
fn send_next( fn send_next(self, tx: &impl MachineOutput) -> Result<Self, Box<dyn std::error::Error>> {
self,
tx: &impl MachineOutput,
) -> Result<Self, Box<dyn std::error::Error>> {
match self.state { match self.state {
State::Propose => { State::Propose => {
tx.send_msg(&Message::Propose(self.version_table.clone()))?; tx.send_msg(&Message::Propose(self.version_table.clone()))?;
@ -193,10 +188,7 @@ impl Agent for Client {
} }
} }
fn receive_next( fn receive_next(self, msg: Self::Message) -> Result<Self, Box<dyn std::error::Error>> {
self,
msg: Self::Message,
) -> Result<Self, Box<dyn std::error::Error>> {
match (self.state, msg) { match (self.state, msg) {
(State::Confirm, Message::Accept(version, data)) => Ok(Self { (State::Confirm, Message::Accept(version, data)) => Ok(Self {
state: State::Done, state: State::Done,