164 lines
5.5 KiB
Rust
164 lines
5.5 KiB
Rust
|
use ethers::prelude::{BlockNumber, U64};
|
||
|
use tracing::warn;
|
||
|
|
||
|
pub fn block_num_to_u64(block_num: BlockNumber, latest_block: U64) -> (bool, U64) {
|
||
|
match block_num {
|
||
|
BlockNumber::Earliest => (false, U64::zero()),
|
||
|
BlockNumber::Latest => {
|
||
|
// change "latest" to a number
|
||
|
(true, latest_block)
|
||
|
}
|
||
|
BlockNumber::Number(x) => (false, x),
|
||
|
BlockNumber::Pending => {
|
||
|
// TODO: think more about how to handle Pending
|
||
|
// modified is false because we probably want the backend to see "pending"
|
||
|
(false, latest_block)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// modify params to always have a block number and not "latest"
|
||
|
pub fn clean_block_number(
|
||
|
params: &mut serde_json::Value,
|
||
|
block_param_id: usize,
|
||
|
latest_block: U64,
|
||
|
) -> anyhow::Result<U64> {
|
||
|
match params.as_array_mut() {
|
||
|
None => Err(anyhow::anyhow!("params not an array")),
|
||
|
Some(params) => match params.get_mut(block_param_id) {
|
||
|
None => {
|
||
|
if params.len() != block_param_id - 1 {
|
||
|
return Err(anyhow::anyhow!("unexpected params length"));
|
||
|
}
|
||
|
|
||
|
// add the latest block number to the end of the params
|
||
|
params.push(serde_json::to_value(latest_block)?);
|
||
|
|
||
|
Ok(latest_block)
|
||
|
}
|
||
|
Some(x) => {
|
||
|
// convert the json value to a BlockNumber
|
||
|
let block_num: BlockNumber = serde_json::from_value(x.clone())?;
|
||
|
|
||
|
let (modified, block_num) = block_num_to_u64(block_num, latest_block);
|
||
|
|
||
|
// if we changed "latest" to a number, update the params to match
|
||
|
if modified {
|
||
|
*x = serde_json::to_value(block_num)?;
|
||
|
}
|
||
|
|
||
|
Ok(block_num)
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO: change this to also return the hash needed
|
||
|
pub fn block_needed(
|
||
|
method: &str,
|
||
|
params: Option<&mut serde_json::Value>,
|
||
|
head_block: U64,
|
||
|
) -> Option<U64> {
|
||
|
let params = params?;
|
||
|
|
||
|
// TODO: double check these. i think some of the getBlock stuff will never need archive
|
||
|
let block_param_id = match method {
|
||
|
"eth_call" => 1,
|
||
|
"eth_estimateGas" => 1,
|
||
|
"eth_getBalance" => 1,
|
||
|
"eth_getBlockByHash" => {
|
||
|
// TODO: double check that any node can serve this
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getBlockByNumber" => {
|
||
|
// TODO: double check that any node can serve this
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getBlockTransactionCountByHash" => {
|
||
|
// TODO: double check that any node can serve this
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getBlockTransactionCountByNumber" => 0,
|
||
|
"eth_getCode" => 1,
|
||
|
"eth_getLogs" => {
|
||
|
let obj = params[0].as_object_mut().unwrap();
|
||
|
|
||
|
if let Some(x) = obj.get_mut("fromBlock") {
|
||
|
let block_num: BlockNumber = serde_json::from_value(x.clone()).ok()?;
|
||
|
|
||
|
let (modified, block_num) = block_num_to_u64(block_num, head_block);
|
||
|
|
||
|
if modified {
|
||
|
*x = serde_json::to_value(block_num).unwrap();
|
||
|
}
|
||
|
|
||
|
return Some(block_num);
|
||
|
}
|
||
|
|
||
|
if let Some(x) = obj.get_mut("toBlock") {
|
||
|
let block_num: BlockNumber = serde_json::from_value(x.clone()).ok()?;
|
||
|
|
||
|
let (modified, block_num) = block_num_to_u64(block_num, head_block);
|
||
|
|
||
|
if modified {
|
||
|
*x = serde_json::to_value(block_num).unwrap();
|
||
|
}
|
||
|
|
||
|
return Some(block_num);
|
||
|
}
|
||
|
|
||
|
if let Some(x) = obj.get("blockHash") {
|
||
|
// TODO: check a linkedhashmap of recent hashes
|
||
|
// TODO: error if fromBlock or toBlock were set
|
||
|
todo!("handle blockHash {}", x);
|
||
|
}
|
||
|
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getStorageAt" => 2,
|
||
|
"eth_getTransactionByHash" => {
|
||
|
// TODO: not sure how best to look these up
|
||
|
// try full nodes first. retry will use archive
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getTransactionByBlockHashAndIndex" => {
|
||
|
// TODO: check a linkedhashmap of recent hashes
|
||
|
// try full nodes first. retry will use archive
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getTransactionByBlockNumberAndIndex" => 0,
|
||
|
"eth_getTransactionCount" => 1,
|
||
|
"eth_getTransactionReceipt" => {
|
||
|
// TODO: not sure how best to look these up
|
||
|
// try full nodes first. retry will use archive
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getUncleByBlockHashAndIndex" => {
|
||
|
// TODO: check a linkedhashmap of recent hashes
|
||
|
// try full nodes first. retry will use archive
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getUncleByBlockNumberAndIndex" => 0,
|
||
|
"eth_getUncleCountByBlockHash" => {
|
||
|
// TODO: check a linkedhashmap of recent hashes
|
||
|
// try full nodes first. retry will use archive
|
||
|
return None;
|
||
|
}
|
||
|
"eth_getUncleCountByBlockNumber" => 0,
|
||
|
_ => {
|
||
|
// some other command that doesn't take block numbers as an argument
|
||
|
return None;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
match clean_block_number(params, block_param_id, head_block) {
|
||
|
Ok(block) => Some(block),
|
||
|
Err(err) => {
|
||
|
// TODO: seems unlikely that we will get here
|
||
|
// if this is incorrect, it should retry on an archive server
|
||
|
warn!(?err, "could not get block from params");
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
}
|