handle functions that need the block num instead of the hash
This commit is contained in:
parent
5f07213c8d
commit
8ea587120b
@ -48,25 +48,60 @@ curl https://eth.llamarpc.com \
|
|||||||
--data '{"method":"eth_getTransactionReceipt","params":["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"],"id":1,"jsonrpc":"2.0"}'
|
--data '{"method":"eth_getTransactionReceipt","params":["0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5"],"id":1,"jsonrpc":"2.0"}'
|
||||||
|
|
||||||
|
|
||||||
--> [
|
curl http://localhost:8544 \
|
||||||
{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
|
-X POST \
|
||||||
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
|
-H "Content-Type: application/json" \
|
||||||
{"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
|
--data '{
|
||||||
{"foo": "boo"},
|
"id": 1,
|
||||||
{"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
|
"jsonrpc": "2.0",
|
||||||
{"jsonrpc": "2.0", "method": "get_data", "id": "9"}
|
"method": "eth_feeHistory",
|
||||||
]
|
"params": [
|
||||||
<-- [
|
4,
|
||||||
{"jsonrpc": "2.0", "result": 7, "id": "1"},
|
4,
|
||||||
{"jsonrpc": "2.0", "result": 19, "id": "2"},
|
4
|
||||||
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
|
||||||
{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
|
|
||||||
{"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
|
|
||||||
]
|
]
|
||||||
|
}'
|
||||||
|
|
||||||
--> [1,2,3]
|
curl https://docs-demo.quiknode.pro/ \
|
||||||
<-- [
|
-X POST \
|
||||||
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
-H "Content-Type: application/json" \
|
||||||
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
--data '{"method":"eth_feeHistory","params":[4, "latest", [25, 75]],"id":1,"jsonrpc":"2.0"}'
|
||||||
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
|
|
||||||
]
|
curl https://ethereum.llamarpc.com/ \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data '{"method":"eth_feeHistory","params":[4, "latest", [25, 75]],"id":1,"jsonrpc":"2.0"}'
|
||||||
|
|
||||||
|
curl http://127.0.0.1:8544/ \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data '{"method":"eth_feeHistory","params":[4, "latest", [25, 75]],"id":1,"jsonrpc":"2.0"}'
|
||||||
|
|
||||||
|
curl http://10.11.12.16:8548/ \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data '{"method":"eth_feeHistory","params":[4, "latest", [25, 75]],"id":1,"jsonrpc":"2.0"}'
|
||||||
|
|
||||||
|
|
||||||
|
# --> [
|
||||||
|
# {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
|
||||||
|
# {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
|
||||||
|
# {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
|
||||||
|
# {"foo": "boo"},
|
||||||
|
# {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
|
||||||
|
# {"jsonrpc": "2.0", "method": "get_data", "id": "9"}
|
||||||
|
# ]
|
||||||
|
# <-- [
|
||||||
|
# {"jsonrpc": "2.0", "result": 7, "id": "1"},
|
||||||
|
# {"jsonrpc": "2.0", "result": 19, "id": "2"},
|
||||||
|
# {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
||||||
|
# {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
|
||||||
|
# {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# --> [1,2,3]
|
||||||
|
# <-- [
|
||||||
|
# {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
||||||
|
# {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
|
||||||
|
# {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
|
||||||
|
# ]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "web3_proxy"
|
name = "web3_proxy"
|
||||||
version = "1.42.3"
|
version = "1.42.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -79,7 +79,7 @@ pub async fn clean_block_number(
|
|||||||
None => {
|
None => {
|
||||||
if params.len() == block_param_id {
|
if params.len() == block_param_id {
|
||||||
// add the latest block number to the end of the params
|
// add the latest block number to the end of the params
|
||||||
params.push(json!(latest_block));
|
params.push(json!(latest_block.number()));
|
||||||
} else {
|
} else {
|
||||||
// don't modify the request. only cache with current block
|
// don't modify the request. only cache with current block
|
||||||
// TODO: more useful log that include the
|
// TODO: more useful log that include the
|
||||||
@ -90,7 +90,9 @@ pub async fn clean_block_number(
|
|||||||
Ok(latest_block.into())
|
Ok(latest_block.into())
|
||||||
}
|
}
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
// convert the json value to a BlockNumber
|
// dig into the json value to find a BlockNumber or similar block identifier
|
||||||
|
trace!(?x, "inspecting");
|
||||||
|
|
||||||
let (block, change) = if let Some(obj) = x.as_object_mut() {
|
let (block, change) = if let Some(obj) = x.as_object_mut() {
|
||||||
// it might be a Map like `{"blockHash": String("0xa5626dc20d3a0a209b1de85521717a3e859698de8ce98bca1b16822b7501f74b")}`
|
// it might be a Map like `{"blockHash": String("0xa5626dc20d3a0a209b1de85521717a3e859698de8ce98bca1b16822b7501f74b")}`
|
||||||
if let Some(block_hash) = obj.get("blockHash").cloned() {
|
if let Some(block_hash) = obj.get("blockHash").cloned() {
|
||||||
@ -159,10 +161,11 @@ pub async fn clean_block_number(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// if we changed "latest" to a hash, update the params to match
|
// if we changed "latest" to an actual block, update the params to match
|
||||||
|
// TODO: should we do hash or number? some functions work with either, but others need a number :cry:
|
||||||
if change {
|
if change {
|
||||||
trace!(old=%x, new=%block.hash(), "changing block number");
|
trace!(old=%x, new=%block.num(), "changing block number");
|
||||||
*x = json!(block.hash());
|
*x = json!(block.num());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
@ -172,6 +175,7 @@ pub async fn clean_block_number(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: change this to also return the hash needed?
|
/// TODO: change this to also return the hash needed?
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum CacheMode {
|
pub enum CacheMode {
|
||||||
CacheSuccessForever,
|
CacheSuccessForever,
|
||||||
CacheNever,
|
CacheNever,
|
||||||
@ -188,6 +192,29 @@ pub enum CacheMode {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_block_param_id(method: &str) -> Option<usize> {
|
||||||
|
match method {
|
||||||
|
"debug_traceBlockByHash" => Some(0),
|
||||||
|
"debug_traceBlockByNumber" => Some(0),
|
||||||
|
"debug_traceCall" => Some(1),
|
||||||
|
"debug_traceTransaction" => None,
|
||||||
|
"eth_call" => Some(1),
|
||||||
|
"eth_estimateGas" => Some(1),
|
||||||
|
"eth_feeHistory" => Some(1),
|
||||||
|
"eth_getBalance" => Some(1),
|
||||||
|
"eth_getBlockReceipts" => Some(0),
|
||||||
|
"eth_getBlockTransactionCountByNumber" => Some(0),
|
||||||
|
"eth_getCode" => Some(1),
|
||||||
|
"eth_getStorageAt" => Some(2),
|
||||||
|
"eth_getTransactionByBlockNumberAndIndex" => Some(0),
|
||||||
|
"eth_getTransactionCount" => Some(1),
|
||||||
|
"eth_getUncleByBlockNumberAndIndex" => Some(0),
|
||||||
|
"eth_getUncleCountByBlockNumber" => Some(0),
|
||||||
|
"trace_call" => Some(2),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CacheMode {
|
impl CacheMode {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
method: &str,
|
method: &str,
|
||||||
@ -197,9 +224,19 @@ impl CacheMode {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
match Self::try_new(method, params, head_block, rpcs).await {
|
match Self::try_new(method, params, head_block, rpcs).await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
|
Err(Web3ProxyError::NoBlocksKnown) => {
|
||||||
|
warn!(%method, ?params, "no servers available to get block from params. caching with head block");
|
||||||
|
CacheMode::Cache {
|
||||||
|
block: head_block.into(),
|
||||||
|
cache_errors: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(?err, "unable to determine cache mode from params");
|
error!(%method, ?params, ?err, "could not get block from params. caching with head block");
|
||||||
Self::CacheNever
|
CacheMode::Cache {
|
||||||
|
block: head_block.into(),
|
||||||
|
cache_errors: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,56 +247,44 @@ impl CacheMode {
|
|||||||
head_block: &Web3ProxyBlock,
|
head_block: &Web3ProxyBlock,
|
||||||
rpcs: &Web3Rpcs,
|
rpcs: &Web3Rpcs,
|
||||||
) -> Web3ProxyResult<Self> {
|
) -> Web3ProxyResult<Self> {
|
||||||
// some requests have potentially very large responses
|
|
||||||
// TODO: only skip caching if the response actually is large
|
|
||||||
if method.starts_with("trace_") || method == "debug_traceTransaction" {
|
|
||||||
return Ok(Self::CacheNever);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(params, serde_json::Value::Null) {
|
if matches!(params, serde_json::Value::Null) {
|
||||||
// no params given
|
// no params given. cache with the head block
|
||||||
return Ok(Self::Cache {
|
return Ok(Self::Cache {
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the index for the BlockNumber
|
match method {
|
||||||
// The BlockNumber is usually the last element.
|
"debug_traceBlockByHash" => {
|
||||||
// TODO: double check these. i think some of the getBlock stuff will never need archive
|
todo!();
|
||||||
let block_param_id = match method {
|
}
|
||||||
"eth_call" => 1,
|
"debug_traceTransaction" => {
|
||||||
"eth_estimateGas" => 1,
|
todo!();
|
||||||
"eth_feeHistory" => 1,
|
}
|
||||||
"eth_gasPrice" => {
|
"eth_gasPrice" => Ok(CacheMode::Cache {
|
||||||
return Ok(CacheMode::Cache {
|
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: false,
|
cache_errors: false,
|
||||||
});
|
}),
|
||||||
}
|
|
||||||
"eth_getBalance" => 1,
|
|
||||||
"eth_getBlockByHash" => {
|
"eth_getBlockByHash" => {
|
||||||
// TODO: double check that any node can serve this
|
// TODO: double check that any node can serve this
|
||||||
// TODO: can a block change? like what if it gets orphaned?
|
// TODO: can a block change? like what if it gets orphaned?
|
||||||
// TODO: make sure re-orgs work properly!
|
// TODO: make sure re-orgs work properly!
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
}
|
}
|
||||||
"eth_getBlockByNumber" => {
|
"eth_getBlockByNumber" => {
|
||||||
// TODO: double check that any node can serve this
|
// TODO: double check that any node can serve this
|
||||||
// TODO: CacheSuccessForever if the block is old enough
|
// TODO: CacheSuccessForever if the block is old enough
|
||||||
// TODO: make sure re-orgs work properly!
|
// TODO: make sure re-orgs work properly!
|
||||||
return Ok(CacheMode::Cache {
|
Ok(CacheMode::Cache {
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
"eth_getBlockReceipts" => 0,
|
|
||||||
"eth_getBlockTransactionCountByHash" => {
|
"eth_getBlockTransactionCountByHash" => {
|
||||||
// TODO: double check that any node can serve this
|
// TODO: double check that any node can serve this
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
}
|
}
|
||||||
"eth_getBlockTransactionCountByNumber" => 0,
|
|
||||||
"eth_getCode" => 1,
|
|
||||||
"eth_getLogs" => {
|
"eth_getLogs" => {
|
||||||
// TODO: think about this more
|
// TODO: think about this more
|
||||||
// TODO: jsonrpc has a specific code for this
|
// TODO: jsonrpc has a specific code for this
|
||||||
@ -272,7 +297,7 @@ impl CacheMode {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
if obj.contains_key("blockHash") {
|
if obj.contains_key("blockHash") {
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
} else {
|
} else {
|
||||||
let from_block = if let Some(x) = obj.get_mut("fromBlock") {
|
let from_block = if let Some(x) = obj.get_mut("fromBlock") {
|
||||||
// TODO: use .take instead of clone
|
// TODO: use .take instead of clone
|
||||||
@ -315,87 +340,107 @@ impl CacheMode {
|
|||||||
head_block.into()
|
head_block.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(CacheMode::CacheRange {
|
Ok(CacheMode::CacheRange {
|
||||||
from_block,
|
from_block,
|
||||||
to_block,
|
to_block,
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"eth_getStorageAt" => 2,
|
|
||||||
"eth_getTransactionByHash" => {
|
"eth_getTransactionByHash" => {
|
||||||
// TODO: not sure how best to look these up
|
// TODO: not sure how best to look these up
|
||||||
// try full nodes first. retry will use archive
|
// try full nodes first. retry will use archive
|
||||||
return Ok(CacheMode::Cache {
|
Ok(CacheMode::Cache {
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
"eth_getTransactionByBlockHashAndIndex" => {
|
"eth_getTransactionByBlockHashAndIndex" => {
|
||||||
// TODO: check a Cache of recent hashes
|
// TODO: check a Cache of recent hashes
|
||||||
// try full nodes first. retry will use archive
|
// try full nodes first. retry will use archive
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
}
|
}
|
||||||
"eth_getTransactionByBlockNumberAndIndex" => 0,
|
|
||||||
"eth_getTransactionCount" => 1,
|
|
||||||
"eth_getTransactionReceipt" => {
|
"eth_getTransactionReceipt" => {
|
||||||
// TODO: not sure how best to look these up
|
// TODO: not sure how best to look these up
|
||||||
// try full nodes first. retry will use archive
|
// try full nodes first. retry will use archive
|
||||||
return Ok(CacheMode::Cache {
|
Ok(CacheMode::Cache {
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
"eth_getUncleByBlockHashAndIndex" => {
|
"eth_getUncleByBlockHashAndIndex" => {
|
||||||
// TODO: check a Cache of recent hashes
|
// TODO: check a Cache of recent hashes
|
||||||
// try full nodes first. retry will use archive
|
// try full nodes first. retry will use archive
|
||||||
// TODO: what happens if this block is uncled later?
|
// TODO: what happens if this block is uncled later?
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
}
|
}
|
||||||
"eth_getUncleByBlockNumberAndIndex" => 0,
|
|
||||||
"eth_getUncleCountByBlockHash" => {
|
"eth_getUncleCountByBlockHash" => {
|
||||||
// TODO: check a Cache of recent hashes
|
// TODO: check a Cache of recent hashes
|
||||||
// try full nodes first. retry will use archive
|
// try full nodes first. retry will use archive
|
||||||
// TODO: what happens if this block is uncled later?
|
// TODO: what happens if this block is uncled later?
|
||||||
return Ok(CacheMode::CacheSuccessForever);
|
Ok(CacheMode::CacheSuccessForever)
|
||||||
}
|
}
|
||||||
"eth_getUncleCountByBlockNumber" => 0,
|
|
||||||
"eth_maxPriorityFeePerGas" => {
|
"eth_maxPriorityFeePerGas" => {
|
||||||
// TODO: this might be too aggressive. i think it can change before a block is mined
|
// TODO: this might be too aggressive. i think it can change before a block is mined
|
||||||
return Ok(CacheMode::Cache {
|
Ok(CacheMode::Cache {
|
||||||
block: head_block.into(),
|
block: head_block.into(),
|
||||||
cache_errors: false,
|
cache_errors: false,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
method => match get_block_param_id(method) {
|
||||||
// some other command that doesn't take block numbers as an argument
|
Some(block_param_id) => {
|
||||||
// since we are caching with the head block, it should be safe to cache_errors
|
let block =
|
||||||
return Ok(CacheMode::Cache {
|
clean_block_number(params, block_param_id, head_block, rpcs).await?;
|
||||||
block: head_block.into(),
|
|
||||||
cache_errors: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match clean_block_number(params, block_param_id, head_block, rpcs).await {
|
Ok(CacheMode::Cache {
|
||||||
Ok(block) => Ok(CacheMode::Cache {
|
|
||||||
block,
|
block,
|
||||||
cache_errors: true,
|
cache_errors: true,
|
||||||
}),
|
|
||||||
Err(Web3ProxyError::NoBlocksKnown) => {
|
|
||||||
warn!(%method, ?params, "no servers available to get block from params");
|
|
||||||
Ok(CacheMode::Cache {
|
|
||||||
block: head_block.into(),
|
|
||||||
cache_errors: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(err) => {
|
None => Err(Web3ProxyError::UnhandledMethod(method.to_string().into())),
|
||||||
error!(%method, ?params, ?err, "could not get block from params");
|
},
|
||||||
Ok(CacheMode::Cache {
|
|
||||||
block: head_block.into(),
|
|
||||||
cache_errors: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::CacheMode;
|
||||||
|
use crate::rpcs::{blockchain::Web3ProxyBlock, many::Web3Rpcs};
|
||||||
|
use ethers::types::{Block, H256};
|
||||||
|
use serde_json::json;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[test_log::test(tokio::test)]
|
||||||
|
async fn test_fee_history() {
|
||||||
|
let method = "eth_feeHistory";
|
||||||
|
let mut params = json!([4, "latest", [25, 75]]);
|
||||||
|
|
||||||
|
let head_block = Block {
|
||||||
|
number: Some(1.into()),
|
||||||
|
hash: Some(H256::random()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let head_block = Web3ProxyBlock::try_new(Arc::new(head_block)).unwrap();
|
||||||
|
|
||||||
|
let (empty, _handle, _ranked_rpc_reciver) =
|
||||||
|
Web3Rpcs::spawn(1, None, 1, 1, "test".into(), None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let x = CacheMode::try_new(method, &mut params, &head_block, &empty)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
x,
|
||||||
|
CacheMode::Cache {
|
||||||
|
block: (&head_block).into(),
|
||||||
|
cache_errors: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(params.get(1), Some(&json!(head_block.number())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@ pub enum Web3ProxyError {
|
|||||||
unknown: U64,
|
unknown: U64,
|
||||||
},
|
},
|
||||||
UnknownKey,
|
UnknownKey,
|
||||||
|
#[error(ignore)]
|
||||||
|
UnhandledMethod(Cow<'static, str>),
|
||||||
UserAgentRequired,
|
UserAgentRequired,
|
||||||
#[error(ignore)]
|
#[error(ignore)]
|
||||||
UserAgentNotAllowed(headers::UserAgent),
|
UserAgentNotAllowed(headers::UserAgent),
|
||||||
@ -1009,6 +1011,12 @@ impl Web3ProxyError {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::UnhandledMethod(method) => {
|
||||||
|
unimplemented!(
|
||||||
|
"unhandled method ({}) should never be shown to a user",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
}
|
||||||
Self::UnknownBlockHash(hash) => {
|
Self::UnknownBlockHash(hash) => {
|
||||||
debug!(%hash, "UnknownBlockHash");
|
debug!(%hash, "UnknownBlockHash");
|
||||||
(
|
(
|
||||||
|
Loading…
Reference in New Issue
Block a user