use eyre::Result; use serde::de::Error; use ssz_rs::prelude::*; use crate::utils::*; pub struct ConsensusRpc { rpc: String, } impl ConsensusRpc { pub fn new(rpc: &str) -> Self { ConsensusRpc { rpc: rpc.to_string(), } } pub async fn get_bootstrap(&self, block_root: &str) -> Result { let req = format!( "{}/eth/v0/beacon/light_client/bootstrap/{}", self.rpc, block_root ); let res = reqwest::get(req).await?.json::().await?; Ok(res.data.v) } pub async fn get_updates(&self, period: u64) -> Result> { let req = format!( "{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000", self.rpc, period ); let res = reqwest::get(req).await?.json::().await?; Ok(res.data) } pub async fn get_finality_update(&self) -> Result { let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.rpc); let res = reqwest::get(req) .await? .json::() .await?; Ok(res.data) } pub async fn get_block(&self, slot: u64) -> Result { let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot); let res = reqwest::get(req) .await? .json::() .await?; Ok(res.data.message) } } pub type BLSPubKey = Vector; pub type SignatureBytes = Vector; pub type Bytes32 = Vector; pub type Address = Vector; pub type LogsBloom = Vector; pub type Transaction = List; #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] pub struct BeaconBlock { #[serde(deserialize_with = "u64_deserialize")] pub slot: u64, #[serde(deserialize_with = "u64_deserialize")] pub proposer_index: u64, #[serde(deserialize_with = "bytes32_deserialize")] pub parent_root: Bytes32, #[serde(deserialize_with = "bytes32_deserialize")] pub state_root: Bytes32, pub body: BeaconBlockBody, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] pub struct BeaconBlockBody { #[serde(deserialize_with = "signature_deserialize")] randao_reveal: SignatureBytes, eth1_data: Eth1Data, #[serde(deserialize_with = "bytes32_deserialize")] graffiti: Bytes32, // TODO: handle proposer_slashings: List, // TODO: handle attester_slashings: List, attestations: List, // TODO: handle deposits: List, // TODO: handle voluntary_exits: List, sync_aggregate: SyncAggregate, pub execution_payload: ExecutionPayload, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] pub struct ExecutionPayload { #[serde(deserialize_with = "bytes32_deserialize")] parent_hash: Bytes32, #[serde(deserialize_with = "address_deserialize")] fee_recipient: Address, #[serde(deserialize_with = "bytes32_deserialize")] pub state_root: Bytes32, #[serde(deserialize_with = "bytes32_deserialize")] pub receipts_root: Bytes32, #[serde(deserialize_with = "logs_bloom_deserialize")] logs_bloom: Vector, #[serde(deserialize_with = "bytes32_deserialize")] prev_randao: Bytes32, #[serde(deserialize_with = "u64_deserialize")] pub block_number: u64, #[serde(deserialize_with = "u64_deserialize")] gas_limit: u64, #[serde(deserialize_with = "u64_deserialize")] gas_used: u64, #[serde(deserialize_with = "u64_deserialize")] timestamp: u64, #[serde(deserialize_with = "extra_data_deserialize")] extra_data: List, #[serde(deserialize_with = "u256_deserialize")] base_fee_per_gas: U256, #[serde(deserialize_with = "bytes32_deserialize")] pub block_hash: Bytes32, #[serde(deserialize_with = "transactions_deserialize")] transactions: List, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] struct Attestation { aggregation_bits: Bitlist<2048>, data: AttestationData, #[serde(deserialize_with = "signature_deserialize")] signature: SignatureBytes, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] struct AttestationData { #[serde(deserialize_with = "u64_deserialize")] slot: u64, #[serde(deserialize_with = "u64_deserialize")] index: u64, #[serde(deserialize_with = "bytes32_deserialize")] beacon_block_root: Bytes32, source: Checkpoint, target: Checkpoint, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] struct Checkpoint { #[serde(deserialize_with = "u64_deserialize")] epoch: u64, #[serde(deserialize_with = "bytes32_deserialize")] root: Bytes32, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] struct Dummy { t: u64, } #[derive(serde::Deserialize, Debug, Default, SimpleSerialize)] pub struct Eth1Data { #[serde(deserialize_with = "bytes32_deserialize")] deposit_root: Bytes32, #[serde(deserialize_with = "u64_deserialize")] deposit_count: u64, #[serde(deserialize_with = "bytes32_deserialize")] block_hash: Bytes32, } #[derive(serde::Deserialize, Debug)] pub struct Bootstrap { pub header: Header, pub current_sync_committee: SyncCommittee, #[serde(deserialize_with = "branch_deserialize")] pub current_sync_committee_branch: Vec, } #[derive(serde::Deserialize, Debug, Clone)] pub struct Update { pub attested_header: Header, pub next_sync_committee: Option, #[serde(deserialize_with = "branch_deserialize")] pub next_sync_committee_branch: Vec, pub finalized_header: Header, #[serde(deserialize_with = "branch_deserialize")] pub finality_branch: Vec, pub sync_aggregate: SyncAggregate, #[serde(deserialize_with = "u64_deserialize")] pub signature_slot: u64, } #[derive(serde::Deserialize, Debug)] pub struct FinalityUpdate { pub attested_header: Header, pub finalized_header: Header, #[serde(deserialize_with = "branch_deserialize")] pub finality_branch: Vec, pub sync_aggregate: SyncAggregate, #[serde(deserialize_with = "u64_deserialize")] pub signature_slot: u64, } #[derive(serde::Deserialize, Debug, Clone, Default, SimpleSerialize)] pub struct Header { #[serde(deserialize_with = "u64_deserialize")] pub slot: u64, #[serde(deserialize_with = "u64_deserialize")] pub proposer_index: u64, #[serde(deserialize_with = "bytes32_deserialize")] pub parent_root: Bytes32, #[serde(deserialize_with = "bytes32_deserialize")] pub state_root: Bytes32, #[serde(deserialize_with = "bytes32_deserialize")] pub body_root: Bytes32, } #[derive(Debug, Clone, Default, SimpleSerialize, serde::Deserialize)] pub struct SyncCommittee { #[serde(deserialize_with = "pubkeys_deserialize")] pub pubkeys: Vector, #[serde(deserialize_with = "pubkey_deserialize")] pub aggregate_pubkey: BLSPubKey, } #[derive(serde::Deserialize, Debug, Clone, Default, SimpleSerialize)] pub struct SyncAggregate { pub sync_committee_bits: Bitvector<512>, #[serde(deserialize_with = "signature_deserialize")] pub sync_committee_signature: SignatureBytes, } #[derive(serde::Deserialize, Debug)] struct BeaconBlockResponse { data: BeaconBlockData, } #[derive(serde::Deserialize, Debug)] struct BeaconBlockData { message: BeaconBlock, } #[derive(serde::Deserialize, Debug)] struct UpdateResponse { data: Vec, } #[derive(serde::Deserialize, Debug)] struct FinalityUpdateResponse { data: FinalityUpdate, } #[derive(serde::Deserialize, Debug)] struct BootstrapResponse { data: BootstrapData, } #[derive(serde::Deserialize, Debug)] struct BootstrapData { v: Bootstrap, } fn pubkey_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let key: String = serde::Deserialize::deserialize(deserializer)?; let key_bytes = hex_str_to_bytes(&key).map_err(D::Error::custom)?; Ok(Vector::from_iter(key_bytes)) } fn pubkeys_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let keys: Vec = serde::Deserialize::deserialize(deserializer)?; Ok(keys .iter() .map(|key| { let key_bytes = hex_str_to_bytes(key)?; Ok(Vector::from_iter(key_bytes)) }) .collect::>>() .map_err(D::Error::custom)?) } fn signature_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let sig: String = serde::Deserialize::deserialize(deserializer)?; let sig_bytes = hex_str_to_bytes(&sig).map_err(D::Error::custom)?; Ok(Vector::from_iter(sig_bytes)) } fn branch_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let branch: Vec = serde::Deserialize::deserialize(deserializer)?; Ok(branch .iter() .map(|elem| { let elem_bytes = hex_str_to_bytes(elem)?; Ok(Vector::from_iter(elem_bytes)) }) .collect::>() .map_err(D::Error::custom)?) } fn u64_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let val: String = serde::Deserialize::deserialize(deserializer)?; Ok(val.parse().unwrap()) } fn u256_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let val: String = serde::Deserialize::deserialize(deserializer)?; // TODO: support larger values let i = val.parse::().map_err(D::Error::custom)?; Ok(U256::from(i)) } fn bytes32_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes: String = serde::Deserialize::deserialize(deserializer)?; let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap(); Ok(bytes.to_vec().try_into().unwrap()) } fn logs_bloom_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes: String = serde::Deserialize::deserialize(deserializer)?; let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap(); Ok(bytes.to_vec().try_into().unwrap()) } fn address_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes: String = serde::Deserialize::deserialize(deserializer)?; let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap(); Ok(bytes.to_vec().try_into().unwrap()) } fn extra_data_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let bytes: String = serde::Deserialize::deserialize(deserializer)?; let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap(); Ok(bytes.to_vec().try_into().unwrap()) } fn transactions_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let transactions: Vec = serde::Deserialize::deserialize(deserializer)?; let transactions = transactions .iter() .map(|tx| { let tx = hex_str_to_bytes(tx).unwrap(); let tx: Transaction = List::from_iter(tx); tx }) .collect::>(); Ok(transactions) }