use crate::jsonrpc::client::HttpClient;
use crate::jsonrpc::error::Web3Error;
use crate::types::{Block, Log, NewFilter, SyncingStatus, TransactionRequest, TransactionResponse};
use crate::types::{ConciseBlock, ConciseXdaiBlock, Data, SendTxOption, XdaiBlock};
use clarity::utils::bytes_to_hex_str;
use clarity::{Address, PrivateKey, Transaction};
use num::{ToPrimitive, Zero};
use num256::Uint256;
use std::cmp::max;
use std::{cmp::min, time::Duration};
use std::{sync::Arc, time::Instant};
use tokio::time::sleep as delay_for;
const ETHEREUM_INTRINSIC_GAS: u32 = 21000;
#[derive(Clone)]
pub struct Web3 {
    url: String,
    jsonrpc_client: Arc<HttpClient>,
    timeout: Duration,
}
impl Web3 {
    pub fn new(url: &str, timeout: Duration) -> Self {
        Self {
            jsonrpc_client: Arc::new(HttpClient::new(url)),
            timeout,
            url: url.to_string(),
        }
    }
    pub fn get_timeout(&self) -> Duration {
        self.timeout
    }
    pub fn get_url(&self) -> String {
        self.url.clone()
    }
    pub async fn eth_accounts(&self) -> Result<Vec<Address>, Web3Error> {
        self.jsonrpc_client
            .request_method("eth_accounts", Vec::<String>::new(), self.timeout)
            .await
    }
        pub async fn eth_chainid(&self) -> Result<Option<Uint256>, Web3Error> {
        let ret: Result<Uint256, Web3Error> = self
            .jsonrpc_client
            .request_method("eth_chainId", Vec::<String>::new(), self.timeout)
            .await;
        Ok(Some(ret?))
    }
    pub async fn net_version(&self) -> Result<u64, Web3Error> {
        let ret: Result<String, Web3Error> = self
            .jsonrpc_client
            .request_method("net_version", Vec::<String>::new(), self.timeout)
            .await;
        Ok(ret?.parse()?)
    }
    pub async fn eth_new_filter(&self, new_filter: NewFilter) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method("eth_newFilter", vec![new_filter], self.timeout)
            .await
    }
    pub async fn eth_get_filter_changes(&self, filter_id: Uint256) -> Result<Vec<Log>, Web3Error> {
        self.jsonrpc_client
            .request_method(
                "eth_getFilterChanges",
                vec![format!("{:#x}", filter_id.clone())],
                self.timeout,
            )
            .await
    }
    pub async fn eth_uninstall_filter(&self, filter_id: Uint256) -> Result<bool, Web3Error> {
        self.jsonrpc_client
            .request_method(
                "eth_uninstallFilter",
                vec![format!("{:#x}", filter_id.clone())],
                self.timeout,
            )
            .await
    }
    pub async fn eth_get_logs(&self, new_filter: NewFilter) -> Result<Vec<Log>, Web3Error> {
        self.jsonrpc_client
            .request_method("eth_getLogs", vec![new_filter], self.timeout)
            .await
    }
    pub async fn eth_get_transaction_count(&self, address: Address) -> Result<Uint256, Web3Error> {
                match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method(
                        "eth_getTransactionCount",
                        vec![address.to_string(), "latest".to_string()],
                        self.timeout,
                    )
                    .await
            }
            true => Err(Web3Error::SyncingNode(
                "Cannot perform eth_getTransactionCount".to_string(),
            )),
        }
    }
                pub async fn eth_gas_price(&self) -> Result<Uint256, Web3Error> {
        match self.eth_syncing().await? {
            false => {
                let median_gas = self
                    .jsonrpc_client
                    .request_method("eth_gasPrice", Vec::<String>::new(), self.timeout)
                    .await?;
                if let Some(gas) = self.get_base_fee_per_gas().await? {
                    if median_gas < gas {
                        Ok(gas)
                    } else {
                        Ok(median_gas)
                    }
                } else {
                    Ok(median_gas)
                }
            }
            _ => Err(Web3Error::SyncingNode(
                "Cannot perform eth_gas_price".to_string(),
            )),
        }
    }
    pub async fn eth_estimate_gas(
        &self,
        transaction: TransactionRequest,
    ) -> Result<Uint256, Web3Error> {
        if let Ok(true) = self.eth_syncing().await {
            warn!("Eth Node is still syncing, request may not work if block is not synced");
        }
        self.jsonrpc_client
            .request_method("eth_estimateGas", vec![transaction], self.timeout)
            .await
    }
    pub async fn eth_get_balance(&self, address: Address) -> Result<Uint256, Web3Error> {
                match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method(
                        "eth_getBalance",
                        vec![address.to_string(), "latest".to_string()],
                        self.timeout,
                    )
                    .await
            }
            true => Err(Web3Error::SyncingNode(
                "Cannot perform eth_getBalance".to_string(),
            )),
        }
    }
        pub async fn eth_syncing(&self) -> Result<bool, Web3Error> {
        let res: SyncingStatus = self
            .jsonrpc_client
            .request_method("eth_syncing", Vec::<String>::new(), self.timeout)
            .await?;
        match res {
            SyncingStatus::Syncing { .. } => Ok(true),
            SyncingStatus::NotSyncing(..) => Ok(false),
        }
    }
    pub async fn eth_send_transaction(
        &self,
        transactions: Vec<TransactionRequest>,
    ) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method("eth_sendTransaction", transactions, self.timeout)
            .await
    }
    pub async fn eth_call(&self, transaction: TransactionRequest) -> Result<Data, Web3Error> {
                match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method("eth_call", (transaction, "latest"), self.timeout)
                    .await
            }
            true => Err(Web3Error::SyncingNode(
                "Cannot perform eth_call".to_string(),
            )),
        }
    }
    pub async fn eth_call_at_height(
        &self,
        transaction: TransactionRequest,
        block: Uint256,
    ) -> Result<Data, Web3Error> {
        let latest_known_block = self.eth_synced_block_number().await?;
        if block <= latest_known_block {
            self.jsonrpc_client
                .request_method(
                    "eth_call",
                    (transaction, format!("{:#x}", block.0)),                     self.timeout,
                )
                .await
        } else if self.eth_syncing().await? {
            Err(Web3Error::SyncingNode(
                "Cannot perform eth_call_at_height".to_string(),
            ))
        } else {
                        Err(Web3Error::BadInput(
                "Cannot perform eth_call_at_height, block number invalid".to_string(),
            ))
        }
    }
        pub async fn eth_synced_block_number(&self) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method("eth_blockNumber", Vec::<String>::new(), self.timeout)
            .await
    }
    pub async fn eth_block_number(&self) -> Result<Uint256, Web3Error> {
        match self.eth_syncing().await? {
            false => self.eth_synced_block_number().await,
            true => Err(Web3Error::SyncingNode(
                "Cannot perform eth_block_number".to_string(),
            )),
        }
    }
    pub async fn eth_get_block_by_number(&self, block_number: Uint256) -> Result<Block, Web3Error> {
        let latest_known_block = self.eth_synced_block_number().await?;
        if block_number <= latest_known_block {
            self.jsonrpc_client
                .request_method(
                    "eth_getBlockByNumber",
                    (format!("{:#x}", block_number), true),
                    self.timeout,
                )
                .await
        } else if self.eth_syncing().await? {
            Err(Web3Error::SyncingNode(
                "Cannot perform eth_get_block_by_number".to_string(),
            ))
        } else {
            Err(Web3Error::BadInput(
                "Cannot perform eth_get_block_by_number, block number invalid".to_string(),
            ))
        }
    }
    pub async fn xdai_get_block_by_number(
        &self,
        block_number: Uint256,
    ) -> Result<XdaiBlock, Web3Error> {
        let latest_known_block = self.eth_synced_block_number().await?;
        if block_number <= latest_known_block {
            self.jsonrpc_client
                .request_method(
                    "eth_getBlockByNumber",
                    (format!("{:#x}", block_number), true),
                    self.timeout,
                )
                .await
        } else if self.eth_syncing().await? {
            Err(Web3Error::SyncingNode(
                "Cannot perform xdai_get_block_by_number".to_string(),
            ))
        } else {
            Err(Web3Error::BadInput(
                "Cannot perform xdai_get_block_by_number, block number invalid".to_string(),
            ))
        }
    }
    pub async fn eth_get_concise_block_by_number(
        &self,
        block_number: Uint256,
    ) -> Result<ConciseBlock, Web3Error> {
        let latest_known_block = self.eth_synced_block_number().await?;
        if block_number <= latest_known_block {
            self.jsonrpc_client
                .request_method(
                    "eth_getBlockByNumber",
                    (format!("{:#x}", block_number), false),
                    self.timeout,
                )
                .await
        } else if self.eth_syncing().await? {
            Err(Web3Error::SyncingNode(
                "Cannot perform eth_get_concise_block_by_number".to_string(),
            ))
        } else {
            Err(Web3Error::BadInput(
                "Cannot perform eth_get_concise_block_by_number, block number invalid".to_string(),
            ))
        }
    }
    pub async fn xdai_get_concise_block_by_number(
        &self,
        block_number: Uint256,
    ) -> Result<ConciseXdaiBlock, Web3Error> {
        let latest_known_block = self.eth_synced_block_number().await?;
        if block_number <= latest_known_block {
            self.jsonrpc_client
                .request_method(
                    "eth_getBlockByNumber",
                    (format!("{:#x}", block_number), false),
                    self.timeout,
                )
                .await
        } else if self.eth_syncing().await? {
            Err(Web3Error::SyncingNode(
                "Cannot perform xdai_get_concise_block_by_number".to_string(),
            ))
        } else {
            Err(Web3Error::BadInput(
                "Cannot perform xdai_get_concise_block_by_number, block number invalid".to_string(),
            ))
        }
    }
    pub async fn eth_get_latest_block(&self) -> Result<ConciseBlock, Web3Error> {
        match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method("eth_getBlockByNumber", ("latest", false), self.timeout)
                    .await
            }
            _ => Err(Web3Error::SyncingNode(
                "Cannot perform eth_get_latest_block".to_string(),
            )),
        }
    }
    pub async fn xdai_get_latest_block(&self) -> Result<ConciseXdaiBlock, Web3Error> {
        match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method("eth_getBlockByNumber", ("latest", false), self.timeout)
                    .await
            }
            _ => Err(Web3Error::SyncingNode(
                "Cannot perform xdai_get_latest_block".to_string(),
            )),
        }
    }
    pub async fn eth_get_latest_block_full(&self) -> Result<Block, Web3Error> {
        match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method("eth_getBlockByNumber", ("latest", true), self.timeout)
                    .await
            }
            _ => Err(Web3Error::SyncingNode(
                "Cannot perform eth_get_latest_block".to_string(),
            )),
        }
    }
    pub async fn xdai_get_latest_block_full(&self) -> Result<XdaiBlock, Web3Error> {
        match self.eth_syncing().await? {
            false => {
                self.jsonrpc_client
                    .request_method("eth_getBlockByNumber", ("latest", true), self.timeout)
                    .await
            }
            _ => Err(Web3Error::SyncingNode(
                "Cannot perform xdai_get_latest_block".to_string(),
            )),
        }
    }
    pub async fn eth_send_raw_transaction(&self, data: Vec<u8>) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method(
                "eth_sendRawTransaction",
                vec![format!("0x{}", bytes_to_hex_str(&data))],
                self.timeout,
            )
            .await
    }
    pub async fn eth_get_transaction_by_hash(
        &self,
        hash: Uint256,
    ) -> Result<Option<TransactionResponse>, Web3Error> {
        if let Ok(true) = self.eth_syncing().await {
            warn!("Eth node is currently syncing, eth_get_transaction_by_hash may not work if transaction is not synced");
        }
        self.jsonrpc_client
            .request_method(
                "eth_getTransactionByHash",
                                                vec![format!("{:#066x}", hash)],
                self.timeout,
            )
            .await
    }
    pub async fn evm_snapshot(&self) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method("evm_snapshot", Vec::<String>::new(), self.timeout)
            .await
    }
    pub async fn evm_revert(&self, snapshot_id: Uint256) -> Result<Uint256, Web3Error> {
        self.jsonrpc_client
            .request_method(
                "evm_revert",
                vec![format!("{:#066x}", snapshot_id)],
                self.timeout,
            )
            .await
    }
                                        pub async fn send_transaction(
        &self,
        to_address: Address,
        data: Vec<u8>,
        value: Uint256,
        own_address: Address,
        secret: PrivateKey,
        options: Vec<SendTxOption>,
    ) -> Result<Uint256, Web3Error> {
        let mut gas_price = None;
        let mut gas_price_multiplier = 1f32;
        let mut gas_limit_multiplier = 1f32;
        let mut gas_limit = None;
        let mut network_id = None;
        let our_balance = self.eth_get_balance(own_address).await?;
        if our_balance.is_zero() || our_balance < ETHEREUM_INTRINSIC_GAS.into() {
                        return Err(Web3Error::InsufficientGas {
                balance: our_balance,
                base_gas: ETHEREUM_INTRINSIC_GAS.into(),
                gas_required: ETHEREUM_INTRINSIC_GAS.into(),
            });
        }
        let mut nonce = self.eth_get_transaction_count(own_address).await?;
        for option in options {
            match option {
                SendTxOption::GasPrice(gp) => gas_price = Some(gp),
                SendTxOption::GasPriceMultiplier(gpm) => gas_price_multiplier = gpm,
                SendTxOption::GasLimitMultiplier(glm) => gas_limit_multiplier = glm,
                SendTxOption::GasLimit(gl) => gas_limit = Some(gl),
                SendTxOption::NetworkId(ni) => network_id = Some(ni),
                SendTxOption::Nonce(n) => nonce = n,
            }
        }
        let mut gas_price = if let Some(gp) = gas_price {
            gp
        } else {
            let gas_price = self.eth_gas_price().await?;
            let f32_gas = gas_price.to_u128();
            if let Some(v) = f32_gas {
                                                ((v as f32 * gas_price_multiplier) as u128).into()
            } else {
                                                gas_price * (gas_price_multiplier.round() as u128).into()
            }
        };
        let mut gas_limit = if let Some(gl) = gas_limit {
            gl
        } else {
            let gas = self
                .simulated_gas_price_and_limit(our_balance.clone())
                .await?;
            self.eth_estimate_gas(TransactionRequest {
                from: Some(own_address),
                to: to_address,
                nonce: Some(nonce.clone().into()),
                gas_price: Some(gas.price.into()),
                gas: Some(gas.limit.into()),
                value: Some(value.clone().into()),
                data: Some(data.clone().into()),
            })
            .await?
        };
                let gas_limit_128 = gas_limit.to_u128();
        if let Some(v) = gas_limit_128 {
            gas_limit = ((v as f32 * gas_limit_multiplier) as u128).into()
        } else {
            gas_limit *= (gas_limit_multiplier.round() as u128).into()
        }
        let network_id = if let Some(ni) = network_id {
            ni
        } else {
            self.net_version().await?
        };
                                        if gas_price.clone() * gas_limit.clone() > our_balance {
            let base_fee_per_gas = self.get_base_fee_per_gas().await?;
            if let Some(base_fee_per_gas) = base_fee_per_gas {
                if base_fee_per_gas.clone() * gas_limit.clone() > our_balance {
                    return Err(Web3Error::InsufficientGas {
                        balance: our_balance,
                        base_gas: base_fee_per_gas,
                        gas_required: gas_limit,
                    });
                }
            }
                                    gas_price = our_balance / gas_limit.clone();
        }
        let transaction = Transaction {
            to: to_address,
            nonce,
            gas_price,
            gas_limit,
            value,
            data,
            signature: None,
        };
        let transaction = transaction.sign(&secret, Some(network_id));
        self.eth_send_raw_transaction(
            transaction
                .to_bytes()
                .expect("transaction.to_bytes() failed"),
        )
        .await
    }
                                            pub async fn simulate_transaction(
        &self,
        contract_address: Address,
        value: Uint256,
        data: Vec<u8>,
        own_address: Address,
        height: Option<Uint256>,
    ) -> Result<Vec<u8>, Web3Error> {
        let our_balance = self.eth_get_balance(own_address).await?;
        if our_balance.is_zero() || our_balance < ETHEREUM_INTRINSIC_GAS.into() {
                        return Err(Web3Error::InsufficientGas {
                balance: our_balance,
                base_gas: ETHEREUM_INTRINSIC_GAS.into(),
                gas_required: ETHEREUM_INTRINSIC_GAS.into(),
            });
        }
        let nonce = self.eth_get_transaction_count(own_address).await?;
        let gas = self.simulated_gas_price_and_limit(our_balance).await?;
        let transaction = TransactionRequest {
            from: Some(own_address),
            to: contract_address,
            gas: Some(gas.limit.into()),
            nonce: Some(nonce.clone().into()),
            gas_price: Some(gas.price.into()),
            value: Some(value.clone().into()),
            data: Some(data.clone().into()),
        };
        match height {
            Some(height) => {
                let bytes = match self.eth_call_at_height(transaction, height).await {
                    Ok(val) => val,
                    Err(e) => return Err(e),
                };
                Ok(bytes.0)
            }
            None => {
                let bytes = match self.eth_call(transaction).await {
                    Ok(val) => val,
                    Err(e) => return Err(e),
                };
                Ok(bytes.0)
            }
        }
    }
                pub async fn wait_for_transaction(
        &self,
        tx_hash: Uint256,
        timeout: Duration,
        blocks_to_wait: Option<Uint256>,
    ) -> Result<TransactionResponse, Web3Error> {
        let start = Instant::now();
        loop {
            delay_for(Duration::from_secs(1)).await;
            match self.eth_get_transaction_by_hash(tx_hash.clone()).await {
                Ok(maybe_transaction) => {
                    if let Some(transaction) = maybe_transaction {
                                                if blocks_to_wait.clone().is_none() && transaction.block_number.is_some() {
                            return Ok(transaction);
                        }
                                                else if let (Some(blocks_to_wait), Some(tx_block)) =
                            (blocks_to_wait.clone(), transaction.block_number.clone())
                        {
                            let current_block = self.eth_block_number().await?;
                                                        if current_block > blocks_to_wait
                                && current_block - blocks_to_wait >= tx_block
                            {
                                return Ok(transaction);
                            }
                        }
                    }
                }
                Err(e) => return Err(e),
            }
            if Instant::now() - start > timeout {
                return Err(Web3Error::TransactionTimeout);
            }
        }
    }
                                                                                                    async fn simulated_gas_price_and_limit(
        &self,
        balance: Uint256,
    ) -> Result<SimulatedGas, Web3Error> {
        const GAS_LIMIT: u128 = 12450000;
        let gas_price = self.eth_gas_price().await?;
        let limit = min(GAS_LIMIT.into(), balance / gas_price.clone());
        Ok(SimulatedGas {
            limit,
            price: gas_price,
        })
    }
                    async fn get_base_fee_per_gas(&self) -> Result<Option<Uint256>, Web3Error> {
        let eth = self.eth_get_latest_block().await;
        let xdai = self.xdai_get_latest_block().await;
                                        match (eth, xdai) {
                                                                        (Ok(eth_block), Ok(xdai_block)) => {
                warn!("Found polyglot blocks! {:?} {:?}", eth_block, xdai_block);
                match (eth_block.base_fee_per_gas, xdai_block.base_fee_per_gas) {
                                        (Some(base_gas_a), Some(base_gas_b)) => Ok(Some(max(base_gas_a, base_gas_b))),
                                                            (Some(base_gas), None) | (None, Some(base_gas)) => Ok(Some(base_gas)),
                    (None, None) => Ok(None),
                }
            }
            (Err(_), Ok(block)) => Ok(block.base_fee_per_gas),
            (Ok(block), Err(_)) => Ok(block.base_fee_per_gas),
                                    (Err(e), Err(_)) => Err(e),
        }
    }
        pub async fn wait_for_next_block(&self, timeout: Duration) -> Result<(), Web3Error> {
        let start = Instant::now();
        let mut last_height: Option<Uint256> = None;
        while Instant::now() - start < timeout {
            match (self.eth_block_number().await, last_height.clone()) {
                (Ok(n), None) => last_height = Some(n),
                (Ok(block_height), Some(last_height)) => {
                    if block_height > last_height {
                        return Ok(());
                    }
                }
                                (Err(_), _) => {}
            }
        }
        Err(Web3Error::NoBlockProduced { time: timeout })
    }
}
struct SimulatedGas {
    limit: Uint256,
    price: Uint256,
}
#[test]
fn test_chain_id() {
    use actix::System;
    let runner = System::new();
    let web3 = Web3::new("https://eth.althea.net", Duration::from_secs(30));
    let web3_xdai = Web3::new("https://dai.althea.net", Duration::from_secs(30));
    runner.block_on(async move {
        assert_eq!(Some(Uint256::from(1u8)), web3.eth_chainid().await.unwrap());
        assert_eq!(
            Some(Uint256::from(100u8)),
            web3_xdai.eth_chainid().await.unwrap()
        );
    })
}
#[test]
fn test_net_version() {
    use actix::System;
    let runner = System::new();
    let web3_xdai = Web3::new("https://dai.altheamesh.com", Duration::from_secs(30));
    let web3 = Web3::new("https://eth.althea.net", Duration::from_secs(30));
    runner.block_on(async move {
        assert_eq!(1u64, web3.net_version().await.unwrap());
        assert_eq!(100u64, web3_xdai.net_version().await.unwrap());
    })
}
#[ignore]
#[test]
fn test_complex_response() {
    use actix::System;
    let runner = System::new();
    let web3 = Web3::new("https://eth.althea.net", Duration::from_secs(30));
    let txid1 = "0x8b9ef028f99016cd3cb8d4168df7491a0bf44f08b678d37f63ab61e782c500ab"
        .parse()
        .unwrap();
    runner.block_on(async move {
        let val = web3.eth_get_transaction_by_hash(txid1).await;
        let val = val.expect("Actix failure");
        let response = val.expect("Failed to parse transaction response");
        assert!(response.block_number.unwrap() > 10u32.into());
    })
}
#[test]
fn test_transaction_count_response() {
    use actix::System;
    let runner = System::new();
    let web3 = Web3::new("https://eth.althea.net", Duration::from_secs(30));
    let address: Address = "0x04668ec2f57cc15c381b461b9fedab5d451c8f7f"
        .parse()
        .unwrap();
    runner.block_on(async move {
        let val = web3.eth_get_transaction_count(address).await;
        let val = val.unwrap();
        assert!(val > 0u32.into());
    });
}
#[test]
fn test_block_response() {
    use actix::System;
    let runner = System::new();
    let web3 = Web3::new("https://eth.althea.net", Duration::from_secs(30));
    runner.block_on(async move {
        let val = web3.eth_get_latest_block().await;
        let val = val.expect("Actix failure");
        assert!(val.number > 10u32.into());
        let val = web3.eth_get_latest_block_full().await;
        let val = val.expect("Actix failure");
        assert!(val.number > 10u32.into());
    });
}
#[test]
fn test_dai_block_response() {
    use actix::System;
    let runner = System::new();
    let web3 = Web3::new("https://dai.althea.net", Duration::from_secs(30));
    runner.block_on(async move {
        let val = web3.xdai_get_latest_block().await;
        let val = val.expect("Actix failure");
        assert!(val.number > 10u32.into());
    });
}
#[ignore]
#[test]
fn test_syncing_check_functions() {
    use actix::System;
    let runner = System::new();
        let web3 = Web3::new("https://dai.althea.net", Duration::from_secs(30));
            runner.block_on(async move {
        let random_address = "0xE04b765c6Ffcc5981DDDcf7e6E2c9E7DB634Df72";
        let val = web3
            .eth_get_balance(Address::parse_and_validate(random_address).unwrap())
            .await;
        println!("{:?}", val);
        let val = web3
            .eth_get_transaction_count(Address::parse_and_validate(random_address).unwrap())
            .await;
        println!("{:?}", val);
        let val = web3.eth_block_number().await;
        println!("{:?}", val);
        let val = web3.eth_synced_block_number().await;
        println!("{:?}", val);
        let val = web3.eth_gas_price().await;
        println!("{:?}", val);
                        
                
                        
        let val = web3
            .eth_get_block_by_number(web3.eth_block_number().await.unwrap())
            .await;
        println!("{:?}", val);
        #[allow(unused_variables)]
        let val = web3.eth_get_block_by_number(20000000_u128.into()).await;
        
        #[allow(unused_variables)]
        let val = web3
            .eth_get_concise_block_by_number(web3.eth_block_number().await.unwrap())
            .await;
        
        let val = web3
            .eth_get_concise_block_by_number(web3.eth_block_number().await.unwrap() + 1_u128.into())
            .await;
        println!("{:?}", val);
        #[allow(unused_variables)]
        let val = web3.eth_get_latest_block().await;
            });
}