-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Serialization improvements #248
Changes from all commits
43a3a0f
1d98d7c
57bb7da
d2719d4
8346e5f
a350696
cf78bd4
f0bdaaf
fb93228
4c9bcf7
bfe9d7d
d1b33ff
95b5870
b7005cf
2a032ab
877df07
5aefc81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,100 @@ | ||
//! CommitSig within Commit | ||
|
||
use crate::serializers; | ||
use crate::serializers::BlockIDFlag; | ||
use crate::serializers::RawCommitSig; | ||
use crate::{account, Signature, Time}; | ||
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; | ||
use serde::{Deserialize, Serialize}; | ||
use std::convert::TryFrom; | ||
|
||
/// BlockIDFlag is used to indicate the validator has voted either for nil, a particular BlockID or was absent. | ||
#[derive(Copy, Clone, Debug, PartialEq)] | ||
pub enum BlockIDFlag { | ||
/// BlockIDFlagAbsent - no vote was received from a validator. | ||
BlockIDFlagAbsent = 1, | ||
/// BlockIDFlagCommit - voted for the Commit.BlockID. | ||
BlockIDFlagCommit = 2, | ||
/// BlockIDFlagNil - voted for nil. | ||
BlockIDFlagNil = 3, | ||
/// CommitSig represents a signature of a validator. | ||
/// It's a part of the Commit and can be used to reconstruct the vote set given the validator set. | ||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] | ||
#[serde(try_from = "RawCommitSig")] | ||
pub enum CommitSig { | ||
/// no vote was received from a validator. | ||
BlockIDFlagAbsent { | ||
/// Validator address | ||
validator_address: account::Id, | ||
}, | ||
/// voted for the Commit.BlockID. | ||
BlockIDFlagCommit { | ||
/// Validator address | ||
validator_address: account::Id, | ||
/// Timestamp of vote | ||
timestamp: Time, | ||
/// Signature of vote | ||
signature: Signature, | ||
}, | ||
/// voted for nil. | ||
BlockIDFlagNil { | ||
/// Validator address | ||
validator_address: account::Id, | ||
/// Timestamp of vote | ||
timestamp: Time, | ||
/// Signature of vote | ||
signature: Signature, | ||
}, | ||
} | ||
|
||
impl BlockIDFlag { | ||
/// Deserialize this type from a byte | ||
pub fn from_u8(byte: u8) -> Option<BlockIDFlag> { | ||
match byte { | ||
1 => Some(BlockIDFlag::BlockIDFlagAbsent), | ||
2 => Some(BlockIDFlag::BlockIDFlagCommit), | ||
3 => Some(BlockIDFlag::BlockIDFlagNil), | ||
_ => None, | ||
/// CommitSig implementation | ||
impl CommitSig { | ||
/// Helper: Extract validator address, since it's always present (according to ADR-025) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We really should clarify this first: #246 (comment) I can very well be that adr isn't representing the full decision anymore, or, that it is slightly confusing nil and absent votes. Also: #196 (comment) cc @melekes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created tracking issue #260 about this. |
||
pub fn validator_address(&self) -> &account::Id { | ||
match &self { | ||
CommitSig::BlockIDFlagAbsent { validator_address } => validator_address, | ||
CommitSig::BlockIDFlagCommit { | ||
validator_address, .. | ||
} => validator_address, | ||
CommitSig::BlockIDFlagNil { | ||
validator_address, .. | ||
} => validator_address, | ||
} | ||
} | ||
|
||
/// Serialize this type as a byte | ||
pub fn to_u8(self) -> u8 { | ||
self as u8 | ||
} | ||
|
||
/// Serialize this type as a 32-bit unsigned integer | ||
pub fn to_u32(self) -> u32 { | ||
self as u32 | ||
} | ||
} | ||
|
||
impl Serialize for BlockIDFlag { | ||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { | ||
self.to_u8().serialize(serializer) | ||
} | ||
} | ||
impl TryFrom<RawCommitSig> for CommitSig { | ||
type Error = &'static str; | ||
|
||
impl<'de> Deserialize<'de> for BlockIDFlag { | ||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { | ||
let byte = u8::deserialize(deserializer)?; | ||
BlockIDFlag::from_u8(byte) | ||
.ok_or_else(|| D::Error::custom(format!("invalid block ID flag: {}", byte))) | ||
} | ||
} | ||
|
||
/// CommitSig represents a signature of a validator. | ||
/// It's a part of the Commit and can be used to reconstruct the vote set given the validator set. | ||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] | ||
pub struct CommitSig { | ||
/// Block ID FLag | ||
pub block_id_flag: BlockIDFlag, | ||
|
||
/// Validator address | ||
#[serde(deserialize_with = "serializers::parse_non_empty_id")] | ||
pub validator_address: Option<account::Id>, | ||
|
||
/// Timestamp | ||
pub timestamp: Time, | ||
|
||
/// Signature | ||
#[serde(deserialize_with = "serializers::parse_non_empty_signature")] | ||
pub signature: Option<Signature>, | ||
} | ||
|
||
impl CommitSig { | ||
/// Checks if a validator's vote is absent | ||
pub fn is_absent(&self) -> bool { | ||
self.block_id_flag == BlockIDFlag::BlockIDFlagAbsent | ||
fn try_from(value: RawCommitSig) -> Result<Self, Self::Error> { | ||
// Validate CommitSig (strict) | ||
match value.block_id_flag { | ||
BlockIDFlag::BlockIDFlagAbsent => { | ||
if value.timestamp.is_some() { | ||
return Err("timestamp is present for BlockIDFlagAbsent CommitSig"); | ||
} | ||
if value.signature.is_some() { | ||
return Err("signature is present for BlockIDFlagAbsent CommitSig"); | ||
} | ||
Ok(CommitSig::BlockIDFlagAbsent { | ||
validator_address: value.validator_address, | ||
}) | ||
} | ||
BlockIDFlag::BlockIDFlagCommit => { | ||
if value.timestamp.is_none() { | ||
Err("timestamp is null for BlockIDFlagCommit CommitSig") | ||
} else if value.signature.is_none() { | ||
Err("signature is null for BlockIDFlagCommit CommitSig") | ||
} else { | ||
Ok(CommitSig::BlockIDFlagCommit { | ||
validator_address: value.validator_address, | ||
timestamp: value.timestamp.unwrap(), | ||
signature: value.signature.unwrap(), | ||
}) | ||
} | ||
} | ||
BlockIDFlag::BlockIDFlagNil => { | ||
if value.timestamp.is_none() { | ||
Err("timestamp is null for BlockIDFlagNil CommitSig") | ||
} else if value.signature.is_none() { | ||
Err("signature is null for BlockIDFlagNil CommitSig") | ||
} else { | ||
Ok(CommitSig::BlockIDFlagNil { | ||
validator_address: value.validator_address, | ||
timestamp: value.timestamp.unwrap(), | ||
signature: value.signature.unwrap(), | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Representing this as an enum is a nice idea 👍