use crate::types::{Address, Bloom, Bytes, H256, U256, U64};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
pub struct Block<TX> {
pub hash: Option<H256>,
#[serde(rename = "parentHash")]
pub parent_hash: H256,
#[serde(rename = "sha3Uncles")]
pub uncles_hash: H256,
#[serde(rename = "miner")]
pub author: Address,
#[serde(rename = "stateRoot")]
pub state_root: H256,
#[serde(rename = "transactionsRoot")]
pub transactions_root: H256,
#[serde(rename = "receiptsRoot")]
pub receipts_root: H256,
pub number: Option<U64>,
#[serde(rename = "gasUsed")]
pub gas_used: U256,
#[serde(rename = "gasLimit")]
pub gas_limit: U256,
#[serde(rename = "extraData")]
pub extra_data: Bytes,
#[serde(rename = "logsBloom")]
pub logs_bloom: Option<Bloom>,
pub timestamp: U256,
pub difficulty: U256,
#[serde(rename = "totalDifficulty")]
pub total_difficulty: Option<U256>,
#[serde(default, rename = "sealFields")]
pub seal_fields: Vec<Bytes>,
pub uncles: Vec<H256>,
pub transactions: Vec<TX>,
pub size: Option<U256>,
#[serde(rename = "mixHash")]
pub mix_hash: Option<H256>,
pub nonce: Option<U64>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BlockId {
Hash(H256),
Number(BlockNumber),
}
impl From<u64> for BlockId {
fn from(num: u64) -> Self {
BlockNumber::Number(num.into()).into()
}
}
impl From<U64> for BlockId {
fn from(num: U64) -> Self {
BlockNumber::Number(num).into()
}
}
impl From<BlockNumber> for BlockId {
fn from(num: BlockNumber) -> Self {
BlockId::Number(num)
}
}
impl From<H256> for BlockId {
fn from(hash: H256) -> Self {
BlockId::Hash(hash)
}
}
impl Serialize for BlockId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
BlockId::Hash(ref x) => {
let mut s = serializer.serialize_struct("BlockIdEip1898", 1)?;
s.serialize_field("blockHash", &format!("{:?}", x))?;
s.end()
}
BlockId::Number(ref num) => num.serialize(serializer),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BlockNumber {
Latest,
Earliest,
Pending,
Number(U64),
}
impl<T: Into<U64>> From<T> for BlockNumber {
fn from(num: T) -> Self {
BlockNumber::Number(num.into())
}
}
impl Serialize for BlockNumber {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
BlockNumber::Number(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
BlockNumber::Latest => serializer.serialize_str("latest"),
BlockNumber::Earliest => serializer.serialize_str("earliest"),
BlockNumber::Pending => serializer.serialize_str("pending"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{Transaction, TxHash};
#[test]
fn deserialize_blk_no_txs() {
let block = r#"{"number":"0x3","hash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","parentHash":"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d","stateRoot":"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b","receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2","miner":"0x0000000000000000000000000000000000000000","difficulty":"0x0","totalDifficulty":"0x0","extraData":"0x","size":"0x3e8","gasLimit":"0x6691b7","gasUsed":"0x5208","timestamp":"0x5ecedbb9","transactions":["0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067"],"uncles":[]}"#;
let _block: Block<TxHash> = serde_json::from_str(&block).unwrap();
}
#[test]
fn deserialize_blk_with_txs() {
let block = r#"{"number":"0x3","hash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","parentHash":"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d","stateRoot":"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b","receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2","miner":"0x0000000000000000000000000000000000000000","difficulty":"0x0","totalDifficulty":"0x0","extraData":"0x","size":"0x3e8","gasLimit":"0x6691b7","gasUsed":"0x5208","timestamp":"0x5ecedbb9","transactions":[{"hash":"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067","nonce":"0x2","blockHash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","blockNumber":"0x3","transactionIndex":"0x0","from":"0xfdcedc3bfca10ecb0890337fbdd1977aba84807a","to":"0xdca8ce283150ab773bcbeb8d38289bdb5661de1e","value":"0x0","gas":"0x15f90","gasPrice":"0x4a817c800","input":"0x","v":"0x25","r":"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88","s":"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e"}],"uncles":[]}"#;
let _block: Block<Transaction> = serde_json::from_str(&block).unwrap();
}
}