use crate::blockdata::transaction::Transaction;
use crate::consensus::encode::{self, Decodable, VarInt};
use crate::cryptonote::hash;
use crate::util::ringct::Signature;
use sealed::sealed;
#[cfg(feature = "serde")]
use serde_crate::{Deserialize, Serialize};
use std::{fmt, io};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_crate"))]
pub enum Vote {
PreVote,
PostVote(u16),
}
impl Default for Vote {
fn default() -> Self {
Vote::PreVote
}
}
impl fmt::Display for Vote {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Vote::PreVote => {
writeln!(fmt, "Pre vote by block")?;
}
Vote::PostVote(vote) => {
writeln!(fmt, "Vote: {}", vote)?;
}
}
Ok(())
}
}
#[sealed]
impl crate::consensus::encode::Encodable for Vote {
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
let mut len = 0;
match self {
Vote::PreVote => Ok(len),
Vote::PostVote(vote) => {
len += vote.consensus_encode(s)?;
Ok(len)
}
}
}
}
impl Vote {
fn consensus_decode<D: io::Read>(
d: &mut D,
major_version: &VarInt,
) -> Result<Vote, encode::Error> {
if major_version >= &VarInt(18) {
let vote: u16 = Decodable::consensus_decode(d)?;
Ok(Vote::PostVote(vote))
} else {
Ok(Vote::PreVote)
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_crate"))]
pub enum MinerSig {
PreSig,
PostSig(Signature),
}
impl Default for MinerSig {
fn default() -> Self {
MinerSig::PreSig
}
}
impl fmt::Display for MinerSig {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
MinerSig::PreSig => {
writeln!(fmt, "Pre MinerSig")?;
}
MinerSig::PostSig(sig) => {
writeln!(fmt, "Miner signature: {}", sig)?;
}
}
Ok(())
}
}
#[sealed]
impl crate::consensus::encode::Encodable for MinerSig {
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
let mut len = 0;
match self {
MinerSig::PreSig => Ok(len),
MinerSig::PostSig(sig) => {
len += sig.consensus_encode(s)?;
Ok(len)
}
}
}
}
impl MinerSig {
fn consensus_decode<D: io::Read>(
d: &mut D,
major_version: &VarInt,
) -> Result<MinerSig, encode::Error> {
if major_version >= &VarInt(18) {
let sig: Signature = Decodable::consensus_decode(d)?;
Ok(MinerSig::PostSig(sig))
} else {
Ok(MinerSig::PreSig)
}
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_crate"))]
pub struct BlockHeader {
pub major_version: VarInt,
pub minor_version: VarInt,
pub timestamp: VarInt,
pub prev_id: hash::Hash,
pub nonce: u32,
pub signature: MinerSig,
pub vote: Vote,
}
impl fmt::Display for BlockHeader {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
writeln!(fmt, "Major version: {}", self.major_version,)?;
writeln!(fmt, "Minor version: {}", self.minor_version,)?;
writeln!(fmt, "Timestamp: {}", self.timestamp,)?;
writeln!(fmt, "Previous id: {}", self.prev_id,)?;
writeln!(fmt, "Nonce: {}", self.nonce,)?;
writeln!(fmt, "Signature: {}", self.signature,)?;
writeln!(fmt, "Vote: {}", self.vote)
}
}
impl Decodable for BlockHeader {
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<BlockHeader, encode::Error> {
let major_version: VarInt = Decodable::consensus_decode(d)?;
let minor_version: VarInt = Decodable::consensus_decode(d)?;
let timestamp: VarInt = Decodable::consensus_decode(d)?;
let prev_id: hash::Hash = Decodable::consensus_decode(d)?;
let nonce: u32 = Decodable::consensus_decode(d)?;
let signature = MinerSig::consensus_decode(d, &major_version)?;
let vote = Vote::consensus_decode(d, &major_version)?;
Ok(BlockHeader {
major_version,
minor_version,
timestamp,
prev_id,
nonce,
signature,
vote,
})
}
}
#[sealed]
impl crate::consensus::encode::Encodable for BlockHeader {
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
let mut len = 0;
len += self.major_version.consensus_encode(s)?;
len += self.minor_version.consensus_encode(s)?;
len += self.timestamp.consensus_encode(s)?;
len += self.prev_id.consensus_encode(s)?;
len += self.nonce.consensus_encode(s)?;
len += self.signature.consensus_encode(s)?;
len += self.vote.consensus_encode(s)?;
Ok(len)
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_crate"))]
pub struct Block {
pub header: BlockHeader,
pub miner_tx: Transaction,
pub tx_hashes: Vec<hash::Hash>,
}
impl fmt::Display for Block {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
writeln!(fmt, "Block header: {}", self.header,)?;
writeln!(fmt, "Miner tx: {}", self.miner_tx)?;
for tx in &self.tx_hashes {
writeln!(fmt, "tx: {}", tx,)?;
}
Ok(())
}
}
impl_consensus_encoding!(Block, header, miner_tx, tx_hashes);
#[cfg(test)]
mod test {
use super::*;
use crate::consensus::encode::deserialize;
use crate::consensus::encode::serialize;
use crate::cryptonote::hash::Hashable;
#[test]
fn test_block_ser_pre_sig() {
let hex = "0808d7c6ffd605b338ed21e6c09427584853b424a87eea47163e4f7e06b16ccdf50f5155430b4477be6d0002f53601ffb93601be84d6f8cdfc03029d99799f49753366da3ad742aac5085360aee627f21a38fb6d93d29ac85d335f34015b19f62f5aa43c094623de7d824e0d9ad1812654d815ad83d1a0163211b68d6b0211000000bb9b02a6000000000100000101000000";
let hex_blockhash_blob="0808d7c6ffd605b338ed21e6c09427584853b424a87eea47163e4f7e06b16ccdf50f5155430b4477be6d00c8dd108dd7da2f115d6265534f4970badd6dc74cc2eec926fa50341981ad1cac01";
let bytes = hex::decode(hex).unwrap();
let block = deserialize::<Block>(&bytes[..]).unwrap();
let header = serialize::<BlockHeader>(&block.header);
let mut count = serialize::<VarInt>(&VarInt(1 + block.tx_hashes.len() as u64));
let mut root = block.miner_tx.hash().0.to_vec(); let mut encode2 = header;
encode2.append(&mut root);
encode2.append(&mut count);
assert_eq!(hex::encode(encode2), hex_blockhash_blob);
let bytes2 = serialize::<Block>(&block);
assert_eq!(bytes, bytes2);
let hex2 = hex::encode(bytes2);
assert_eq!(hex, hex2);
}
#[test]
fn test_block_ser_post_sig() {
let hex = "1313aee6e69206bd69bc9aa035073458c550577631d0880b1bc86a4d12ba54a73abc87abd2d6ff0bfa0bcfb2aee1cf7379455aae8ca93048767d5fceaa1fe07701e74e56e0d8f1ad6e9202009c33772db196bc3ff1189a3dc3454ec74dff92054720577aec59e9083afc02000002fc9f1901ffdc9d19019af3c7b197d9020206f3b155076296ce7ea499348439775a6c4fecca8bcc0a7ea8b1ff31e8028fa72b01f6affc050bc0b2539f6a78f74206d38a68e1a1afe6411e37dd2c4c2cad176c7b0208defc772e10c708ab0000";
let hex_blockhash_blob="1313aee6e69206bd69bc9aa035073458c550577631d0880b1bc86a4d12ba54a73abc87abd2d6ff0bfa0bcfb2aee1cf7379455aae8ca93048767d5fceaa1fe07701e74e56e0d8f1ad6e9202009c33772db196bc3ff1189a3dc3454ec74dff92054720577aec59e9083afc020000c1354695b547ef9a134eb93eba9e33681e92ff90c97c8f06f1ed9b1d08e2e78501";
let bytes = hex::decode(hex).unwrap();
let block = deserialize::<Block>(&bytes[..]).unwrap();
let header = serialize::<BlockHeader>(&block.header);
let mut count = serialize::<VarInt>(&VarInt(1 + block.tx_hashes.len() as u64));
let mut root = block.miner_tx.hash().0.to_vec(); let mut encode2 = header;
encode2.append(&mut root);
encode2.append(&mut count);
assert_eq!(hex::encode(encode2), hex_blockhash_blob);
let bytes2 = serialize::<Block>(&block);
assert_eq!(bytes, bytes2);
let hex2 = hex::encode(bytes2);
assert_eq!(hex, hex2);
}
#[test]
fn test_block_ser() {
let hex = "1313e8e8e69206fadcd0e9131d5eb096d630e7316e6f0bfe62c1faf7dea5a52dfe51f423efe065c2810bcf17f729c5f733e540ee25f57c42f948a7dac4e96d84d60c38525d3397b6984101137be1cedda414681fa250739c603772121cbe065b90ee780abca9163f3b7309000002fe9f1901ffde9d1901a6fae18898d90202d4caf7bc40cf60734fc088b1cdfbef7723333ba8d194b881f4a86f78a437fe452b019d60dd68184e4e9e9b0684825393951c617968fe84e91ecd07a057aee9e60da8020873fcc8522e0780400001c50ecadac939ae36053dd9257275506e29eadf58758972f8c583a4362f1584e6";
let hex_blockhash_blob="1313e8e8e69206fadcd0e9131d5eb096d630e7316e6f0bfe62c1faf7dea5a52dfe51f423efe065c2810bcf17f729c5f733e540ee25f57c42f948a7dac4e96d84d60c38525d3397b6984101137be1cedda414681fa250739c603772121cbe065b90ee780abca9163f3b73090000d7dc7273061b14bc0580b85ef653d61ee3e00fcf5e6a60fa8fd78707bb8eaf7402";
let bytes = hex::decode(hex).unwrap();
let block = deserialize::<Block>(&bytes[..]).unwrap();
let header = serialize::<BlockHeader>(&block.header);
let mut count = serialize::<VarInt>(&VarInt(1 + block.tx_hashes.len() as u64));
let mut root = block.miner_tx.hash().0.to_vec(); let mut encode2 = header;
encode2.append(&mut root);
encode2.append(&mut count);
assert_eq!(hex::encode(encode2), hex_blockhash_blob);
let bytes2 = serialize::<Block>(&block);
assert_eq!(bytes, bytes2);
let hex2 = hex::encode(bytes2);
assert_eq!(hex, hex2);
assert_eq!(
"c50ecadac939ae36053dd9257275506e29eadf58758972f8c583a4362f1584e6",
hex::encode(block.tx_hashes[0])
);
}
}