use crate::{bloom::Bloom, debug, serialization};
use ethprim::AsU256 as _;
use serde::{
de::{self, Deserializer},
ser::Serializer,
Deserialize, Serialize,
};
use std::{
collections::HashMap,
fmt::{self, Debug, Formatter},
};
pub use ethprim::{Address, Digest, I256, U256};
pub struct Empty;
impl<'de> Deserialize<'de> for Empty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
<[(); 0]>::deserialize(deserializer)?;
Ok(Empty)
}
}
impl Serialize for Empty {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
[(); 0].serialize(serializer)
}
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BlockSpec {
Number(U256),
Tag(BlockTag),
}
impl Default for BlockSpec {
fn default() -> Self {
Self::Tag(Default::default())
}
}
impl From<U256> for BlockSpec {
fn from(number: U256) -> Self {
Self::Number(number)
}
}
impl From<u64> for BlockSpec {
fn from(number: u64) -> Self {
number.as_u256().into()
}
}
impl From<BlockTag> for BlockSpec {
fn from(tag: BlockTag) -> Self {
Self::Tag(tag)
}
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BlockId {
Number(U256),
Hash(Digest),
Tag(BlockTag),
}
impl Default for BlockId {
fn default() -> Self {
Self::Tag(Default::default())
}
}
impl From<U256> for BlockId {
fn from(number: U256) -> Self {
Self::Number(number)
}
}
impl From<u64> for BlockId {
fn from(number: u64) -> Self {
number.as_u256().into()
}
}
impl From<BlockTag> for BlockId {
fn from(tag: BlockTag) -> Self {
Self::Tag(tag)
}
}
impl From<BlockSpec> for BlockId {
fn from(spec: BlockSpec) -> Self {
match spec {
BlockSpec::Number(number) => Self::Number(number),
BlockSpec::Tag(tag) => Self::Tag(tag),
}
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum BlockTag {
Earliest,
Finalized,
Safe,
#[default]
Latest,
Pending,
}
#[derive(Clone, Copy, Debug, Default)]
pub enum Hydrated {
#[default]
No,
Yes,
}
impl Hydrated {
fn from_bool(value: bool) -> Self {
match value {
false => Self::No,
true => Self::Yes,
}
}
fn as_bool(&self) -> bool {
match self {
Self::No => false,
Self::Yes => true,
}
}
}
impl Serialize for Hydrated {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_bool().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Hydrated {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
bool::deserialize(deserializer).map(Self::from_bool)
}
}
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct BlockNonce(pub [u8; 8]);
impl Debug for BlockNonce {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_tuple("BlockNonce")
.field(&debug::Hex(&self.0))
.finish()
}
}
impl Serialize for BlockNonce {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialization::bytearray::serialize(&self.0, serializer)
}
}
impl<'de> Deserialize<'de> for BlockNonce {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
serialization::bytearray::deserialize(deserializer).map(Self)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BlockTransactions {
Hash(Vec<Digest>),
Full(Vec<SignedTransaction>),
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum SignedTransaction {
#[serde(rename = "0x0")]
Legacy(SignedLegacyTransaction),
#[serde(rename = "0x1")]
Erc2930(SignedErc2930Transaction),
#[serde(rename = "0x2")]
Erc1559(SignedErc1559Transaction),
}
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd, Deserialize, Serialize)]
pub enum YParity {
#[serde(rename = "0x0")]
Even = 0,
#[serde(rename = "0x1")]
Odd = 1,
}
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SignedLegacyTransaction {
pub nonce: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<Address>,
pub gas: U256,
pub value: U256,
#[serde(with = "serialization::bytes")]
pub input: Vec<u8>,
pub gas_price: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain_id: Option<U256>,
pub v: U256,
pub r: U256,
pub s: U256,
}
impl Debug for SignedLegacyTransaction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("SignedLegacyTransaction")
.field("nonce", &self.nonce)
.field("to", &self.to)
.field("gas", &self.gas)
.field("value", &self.value)
.field("input", &debug::Hex(&self.input))
.field("gas_price", &self.gas_price)
.field("chain_id", &self.chain_id)
.field("v", &self.v)
.field("r", &self.r)
.field("s", &self.s)
.finish()
}
}
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SignedErc2930Transaction {
pub nonce: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<Address>,
pub gas: U256,
pub value: U256,
#[serde(with = "serialization::bytes")]
pub input: Vec<u8>,
pub gas_price: U256,
pub access_list: AccessList,
pub chain_id: U256,
#[serde(alias = "v")]
pub y_parity: YParity,
pub r: U256,
pub s: U256,
}
impl Debug for SignedErc2930Transaction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("SignedErc2930Transaction")
.field("nonce", &self.nonce)
.field("to", &self.to)
.field("gas", &self.gas)
.field("value", &self.value)
.field("input", &debug::Hex(&self.input))
.field("gas_price", &self.gas_price)
.field("access_list", &self.access_list)
.field("chain_id", &self.chain_id)
.field("y_parity", &self.y_parity)
.field("r", &self.r)
.field("s", &self.s)
.finish()
}
}
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SignedErc1559Transaction {
pub nonce: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<Address>,
pub gas: U256,
pub value: U256,
#[serde(with = "serialization::bytes")]
pub input: Vec<u8>,
pub max_priority_fee_per_gas: U256,
pub max_fee_per_gas: U256,
pub access_list: AccessList,
pub chain_id: U256,
#[serde(alias = "v")]
pub y_parity: YParity,
pub r: U256,
pub s: U256,
}
impl Debug for SignedErc1559Transaction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("SignedErc1559Transaction")
.field("nonce", &self.nonce)
.field("to", &self.to)
.field("gas", &self.gas)
.field("value", &self.value)
.field("input", &debug::Hex(&self.input))
.field("max_priority_fee_per_gas", &self.max_priority_fee_per_gas)
.field("max_fee_per_gas", &self.max_fee_per_gas)
.field("access_list", &self.access_list)
.field("chain_id", &self.chain_id)
.field("y_parity", &self.y_parity)
.field("r", &self.r)
.field("s", &self.s)
.finish()
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Withdrawal {
#[serde(with = "serialization::num")]
pub index: u64,
#[serde(with = "serialization::num")]
pub validator_index: u64,
#[serde(with = "serialization::num")]
pub amount: u128,
}
#[derive(Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Block {
pub hash: Digest,
pub parent_hash: Digest,
pub sha3_uncles: Digest,
pub miner: Address,
pub state_root: Digest,
pub transactions_root: Digest,
pub receipts_root: Digest,
pub logs_bloom: Bloom,
#[serde(skip_serializing_if = "Option::is_none")]
pub difficulty: Option<U256>,
pub number: U256,
pub gas_limit: U256,
pub gas_used: U256,
pub timestamp: U256,
#[serde(with = "serialization::bytes")]
pub extra_data: Vec<u8>,
pub mix_hash: Digest,
pub nonce: BlockNonce,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_difficulty: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub base_fee_per_gas: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub withdrawals_root: Option<Digest>,
pub size: U256,
pub transactions: Vec<SignedTransaction>,
#[serde(skip_serializing_if = "Option::is_none")]
pub withdrawals: Option<Vec<Withdrawal>>,
pub uncles: Vec<Digest>,
}
impl Debug for Block {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Block")
.field("hash", &self.hash)
.field("parent_hash", &self.parent_hash)
.field("sha3_uncles", &self.sha3_uncles)
.field("miner", &self.miner)
.field("state_root", &self.state_root)
.field("transactions_root", &self.transactions_root)
.field("receipts_root", &self.receipts_root)
.field("logs_bloom", &self.logs_bloom)
.field("difficulty", &self.difficulty)
.field("number", &self.number)
.field("gas_limit", &self.gas_limit)
.field("gas_used", &self.gas_used)
.field("timestamp", &self.timestamp)
.field("extra_data", &debug::Hex(&self.extra_data))
.field("mix_hash", &self.mix_hash)
.field("nonce", &self.nonce)
.field("total_difficulty", &self.total_difficulty)
.field("base_fee_per_gas", &self.base_fee_per_gas)
.field("withdrawals_root", &self.withdrawals_root)
.field("size", &self.size)
.field("transactions", &self.transactions)
.field("withdrawals", &self.withdrawals)
.field("uncles", &self.uncles)
.finish()
}
}
#[derive(Clone, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionCall {
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<Address>,
pub kind: Option<TransactionKind>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nonce: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<Address>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gas: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<U256>,
#[serde(
skip_serializing_if = "Option::is_none",
with = "serialization::option_bytes"
)]
pub input: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_price: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_priority_fee_per_gas: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_fee_per_gas: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub access_list: Option<AccessList>,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain_id: Option<U256>,
}
impl Debug for TransactionCall {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("TransactionCall")
.field("from", &self.from)
.field("kind", &self.kind)
.field("nonce", &self.nonce)
.field("to", &self.to)
.field("gas", &self.gas)
.field("value", &self.value)
.field("input", &self.input.as_deref().map(debug::Hex))
.field("gas_price", &self.gas_price)
.field("max_priority_fee_per_gas", &self.max_priority_fee_per_gas)
.field("max_fee_per_gas", &self.max_fee_per_gas)
.field("access_list", &self.access_list)
.field("chain_id", &self.chain_id)
.finish()
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[repr(u8)]
pub enum TransactionKind {
#[default]
Legacy = 0,
Erc2930 = 1,
Erc1559 = 2,
}
impl Serialize for TransactionKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
(*self as u8).as_u256().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for TransactionKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = U256::deserialize(deserializer)?;
match u8::try_from(value) {
Ok(0) => Ok(Self::Legacy),
Ok(1) => Ok(Self::Erc2930),
Ok(2) => Ok(Self::Erc1559),
_ => Err(de::Error::custom(format!(
"invalid transaction type {value}"
))),
}
}
}
pub type AccessList = Vec<AccessListEntry>;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AccessListEntry {
pub address: Address,
pub storage_keys: Vec<U256>,
}
pub type StateOverrides = HashMap<Address, StateOverride>;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StateOverride {
#[serde(skip_serializing_if = "Option::is_none")]
pub balance: Option<U256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nonce: Option<U256>,
#[serde(
skip_serializing_if = "Option::is_none",
with = "serialization::option_bytes"
)]
pub code: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<HashMap<U256, U256>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state_diff: Option<HashMap<U256, U256>>,
}