Skip to content

Commit

Permalink
Add filter RPC endpoints (#3979)
Browse files Browse the repository at this point in the history
* add new eth_filter_module rpc module

* add rpc endpoints

* update arguments

* add FilterChanges type

* update changelog

* fix clppy

* add eth_getLogs endpoint

* update suggestion
  • Loading branch information
Mr-Leshiy authored May 17, 2022
1 parent 9f6cecf commit aae53ff
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- Add new Ethreum RPC endpoints for transaction handling: eth_sendTransaction, eth_sendRawTransaction, eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getTransactionReceipt, eth_signTransaction, eth_estimateGas, eth_sign, eth_call
- Add new Ethreum RPC endpoints for getting chain info: eth_chainId, eth_syncing, eth_gasPrice, eth_protocolVersion, eth_feeHistory
- Add new Ethreum RPC endpoints for account handling: eth_accounts, eth_getTransactionCount, eth_getBalance, eth_getCode, eth_getStorageAt
- Add new Ethreum RPC filtering endpoints: eth_newFilter, eth_newBlockFilter, eth_newPendingTransactionFilter, eth_uninstallFilter, eth_getFilterChanges, eth_getFilterLogs, eth_getLogs
- Add new Ethreum RPC mining endpoints: eth_mining, eth_coinbase, eth_hashrate, eth_getWork, eth_submitWork, eth_submitHashrate
- Add chain-evm as optional dependency for jcli
- Update gas price and block gas limit for EVM params
Expand Down
44 changes: 44 additions & 0 deletions jormungandr/src/jrpc/eth_filter/logic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use super::Error;
use crate::{
context::Context,
jrpc::eth_types::{
filter::{Filter, FilterChanges},
log::Log,
number::Number,
},
};

pub fn new_filter(_filter: Filter, _context: &Context) -> Result<Number, Error> {
// TODO implement
Ok(0.into())
}

pub fn new_block_filter(_context: &Context) -> Result<Number, Error> {
// TODO implement
Ok(0.into())
}

pub fn new_pending_transaction_filter(_context: &Context) -> Result<Number, Error> {
// TODO implement
Ok(0.into())
}

pub fn uninstall_filter(_filter_id: Number, _context: &Context) -> Result<bool, Error> {
// TODO implement
Ok(true)
}

pub fn get_filter_changes(_filter_id: Number, _context: &Context) -> Result<FilterChanges, Error> {
// TODO implement
Ok(FilterChanges::Empty)
}

pub fn get_filter_logs(_filter_id: Number, _context: &Context) -> Result<Vec<Log>, Error> {
// TODO implement
Ok(vec![Log::build()])
}

pub fn get_logs(_filter: Filter, _context: &Context) -> Result<FilterChanges, Error> {
// TODO implement
Ok(FilterChanges::Empty)
}
73 changes: 73 additions & 0 deletions jormungandr/src/jrpc/eth_filter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::context::ContextLock;
use jsonrpsee_http_server::RpcModule;

mod logic;

#[derive(Debug, thiserror::Error)]
pub enum Error {}

pub fn eth_filter_module(context: ContextLock) -> RpcModule<ContextLock> {
let mut module = RpcModule::new(context);

module
.register_async_method("eth_newFilter", |params, context| async move {
let context = context.read().await;
let filter = params.parse()?;
logic::new_filter(filter, &context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_newBlockFilter", |_, context| async move {
let context = context.read().await;
logic::new_block_filter(&context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_newPendingTransactionFilter", |_, context| async move {
let context = context.read().await;
logic::new_pending_transaction_filter(&context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_uninstallFilter", |params, context| async move {
let context = context.read().await;
let filter_id = params.parse()?;
logic::uninstall_filter(filter_id, &context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_getFilterChanges", |params, context| async move {
let context = context.read().await;
let filter_id = params.parse()?;
logic::get_filter_changes(filter_id, &context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_getFilterLogs", |params, context| async move {
let context = context.read().await;
let filter_id = params.parse()?;
logic::get_filter_logs(filter_id, &context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();

module
.register_async_method("eth_getLogs", |params, context| async move {
let context = context.read().await;
let filter = params.parse()?;
logic::get_logs(filter, &context)
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
}
143 changes: 143 additions & 0 deletions jormungandr/src/jrpc/eth_types/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use super::{block_number::BlockNumber, log::Log};
use chain_evm::ethereum_types::{H160, H256};
use serde::{Deserialize, Serialize, Serializer};

/// Variadic value
#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum VariadicValue<T> {
/// Single
Single(T),
/// List
Multiple(Vec<T>),
/// None
Null,
}

/// Filter Address
pub type FilterAddress = VariadicValue<H160>;
/// Topic, supports `A` | `null` | `[A,B,C]` | `[A,[B,C]]` | [null,[B,C]] | [null,[null,C]]
pub type Topic = VariadicValue<VariadicValue<H256>>;

/// Filter
#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")]
pub struct Filter {
/// From Block
from_block: Option<BlockNumber>,
/// To Block
to_block: Option<BlockNumber>,
/// Address
address: FilterAddress,
/// Topics
topics: Topic,
/// Block hash
block_hash: Option<H256>,
}

/// Results of the filter_changes RPC.
#[derive(Debug, PartialEq, Eq)]
pub enum FilterChanges {
#[allow(dead_code)]
/// New logs.
Logs(Vec<Log>),
#[allow(dead_code)]
/// New hashes (block or transactions)
Hashes(Vec<H256>),
/// Empty result,
Empty,
}

impl Serialize for FilterChanges {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
FilterChanges::Logs(ref logs) => logs.serialize(s),
FilterChanges::Hashes(ref hashes) => hashes.serialize(s),
FilterChanges::Empty => (&[] as &[serde_json::Value]).serialize(s),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn filter_address_deserialize() {
let fa_single: FilterAddress =
serde_json::from_str(r#""0x0000000000000000000000000000000000000000""#).unwrap();
let fa_multiple: FilterAddress =
serde_json::from_str(r#"["0x0000000000000000000000000000000000000000"]"#).unwrap();
let fa_null: FilterAddress = serde_json::from_str(r#"null"#).unwrap();

assert_eq!(fa_single, FilterAddress::Single(H160::zero()));
assert_eq!(fa_multiple, FilterAddress::Multiple(vec![H160::zero()]));
assert_eq!(fa_null, FilterAddress::Null);
}

#[test]
fn topic_deserialize() {
let t_single_single: Topic = serde_json::from_str(
r#""0x0000000000000000000000000000000000000000000000000000000000000000""#,
)
.unwrap();
let t_single_multiple: Topic = serde_json::from_str(
r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#,
)
.unwrap();
let t_multiple_multiple_1: Topic = serde_json::from_str(
r#"["0x0000000000000000000000000000000000000000000000000000000000000000",["0x0000000000000000000000000000000000000000000000000000000000000000"]]"#,
)
.unwrap();
let t_multiple_multiple_2: Topic = serde_json::from_str(
r#"[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]]"#,
)
.unwrap();
let t_null: Topic = serde_json::from_str(r#"null"#).unwrap();

assert_eq!(
t_single_single,
Topic::Single(<VariadicValue<H256>>::Single(H256::zero()))
);
assert_eq!(
t_single_multiple,
Topic::Single(<VariadicValue<H256>>::Multiple(vec![H256::zero()]))
);
assert_eq!(
t_multiple_multiple_1,
Topic::Multiple(vec![
<VariadicValue<H256>>::Single(H256::zero()),
<VariadicValue<H256>>::Multiple(vec![H256::zero()])
])
);
assert_eq!(
t_multiple_multiple_2,
Topic::Multiple(vec![
<VariadicValue<H256>>::Null,
<VariadicValue<H256>>::Multiple(vec![H256::zero()])
])
);
assert_eq!(t_null, Topic::Single(<VariadicValue<H256>>::Null));
}

#[test]
fn filter_changes_serialize() {
let fc_log = FilterChanges::Logs(vec![Log::build()]);
let fc_hashes = FilterChanges::Hashes(vec![H256::zero()]);
let fc_empty = FilterChanges::Empty;

assert_eq!(
serde_json::to_string(&fc_log).unwrap(),
r#"[{"removed":true,"logIndex":"0x1","transactionIndex":"0x1","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","address":"0x0000000000000000000000000000000000000000","data":"0x","topics":[]}]"#
);
assert_eq!(
serde_json::to_string(&fc_hashes).unwrap(),
r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#
);
assert_eq!(serde_json::to_string(&fc_empty).unwrap(), r#"[]"#);
}
}
1 change: 1 addition & 0 deletions jormungandr/src/jrpc/eth_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod block;
pub mod block_number;
pub mod bytes;
pub mod fee;
pub mod filter;
pub mod log;
pub mod number;
pub mod receipt;
Expand Down
2 changes: 1 addition & 1 deletion jormungandr/src/jrpc/eth_types/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ mod tests {
use super::*;

#[test]
fn index_deserialization() {
fn number_serde() {
let s = r#"["0xa", "10", 42, "0x45"]"#;
let deserialized: Vec<Number> = serde_json::from_str(s).unwrap();
assert_eq!(
Expand Down
6 changes: 6 additions & 0 deletions jormungandr/src/jrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod eth_block_info;
#[cfg(feature = "evm")]
mod eth_chain_info;
#[cfg(feature = "evm")]
mod eth_filter;
#[cfg(feature = "evm")]
mod eth_miner;
#[cfg(feature = "evm")]
mod eth_transaction;
Expand Down Expand Up @@ -46,6 +48,10 @@ pub async fn start_jrpc_server(config: Config, _context: ContextLock) {
.merge(eth_account::eth_account_module(_context.clone()))
.unwrap();

modules
.merge(eth_filter::eth_filter_module(_context.clone()))
.unwrap();

modules
.merge(eth_miner::eth_miner_module(_context))
.unwrap();
Expand Down

0 comments on commit aae53ff

Please sign in to comment.