diff --git a/src/addons/hl_node_compliance.rs b/src/addons/hl_node_compliance.rs index 41e618d29..6c44487bf 100644 --- a/src/addons/hl_node_compliance.rs +++ b/src/addons/hl_node_compliance.rs @@ -7,13 +7,14 @@ //! For non-system transactions, we can just return the log as is, and the client will //! adjust the transaction index accordingly. -use alloy_consensus::{transaction::TransactionMeta, TxReceipt}; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader, TxReceipt}; use alloy_eips::{BlockId, BlockNumberOrTag}; use alloy_json_rpc::RpcObject; use alloy_primitives::{B256, U256}; use alloy_rpc_types::{ pubsub::{Params, SubscriptionKind}, BlockTransactions, Filter, FilterChanges, FilterId, Log, PendingTransactionFilterKind, + TransactionInfo, }; use jsonrpsee::{proc_macros::rpc, PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink}; use jsonrpsee_core::{async_trait, RpcResult}; @@ -71,6 +72,88 @@ impl EthWrapper for T where { } +#[rpc(server, namespace = "eth")] +#[async_trait] +pub trait EthSystemTransactionApi { + #[method(name = "getSystemTxsByBlockHash")] + async fn get_system_txs_by_block_hash(&self, hash: B256) -> RpcResult>>; + + #[method(name = "getSystemTxsByBlockNumber")] + async fn get_system_txs_by_block_number( + &self, + block_id: Option, + ) -> RpcResult>>; +} + +pub struct HlSystemTransactionExt { + eth_api: Eth, + _marker: PhantomData, +} + +impl HlSystemTransactionExt { + pub fn new(eth_api: Eth) -> Self { + Self { eth_api, _marker: PhantomData } + } +} + +#[async_trait] +impl EthSystemTransactionApiServer> + for HlSystemTransactionExt +where + jsonrpsee_types::ErrorObject<'static>: From<::Error>, +{ + /// Returns the system transactions for a given block hash. + /// Compliance with the `eth_getSystemTxsByBlockHash` RPC method introduced by hl-node. + /// https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc + async fn get_system_txs_by_block_hash( + &self, + hash: B256, + ) -> RpcResult>>> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getSystemTxsByBlockHash"); + self.get_system_txs_by_block_number(Some(BlockId::Hash(hash.into()))).await + } + + /// Returns the system transactions for a given block number, or the latest block if no block + /// number is provided. Compliance with the `eth_getSystemTxsByBlockNumber` RPC method + /// introduced by hl-node. https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc + async fn get_system_txs_by_block_number( + &self, + id: Option, + ) -> RpcResult>>> { + trace!(target: "rpc::eth", ?id, "Serving eth_getSystemTxsByBlockNumber"); + + if let Some(block) = self.eth_api.recovered_block(id.unwrap_or_default()).await? { + let block_hash = block.hash(); + let block_number = block.number(); + let base_fee_per_gas = block.base_fee_per_gas(); + let system_txs = block + .transactions_with_sender() + .enumerate() + .filter_map(|(index, (signer, tx))| { + if tx.is_system_transaction() { + let tx_info = TransactionInfo { + hash: Some(*tx.tx_hash()), + block_hash: Some(block_hash), + block_number: Some(block_number), + base_fee: base_fee_per_gas, + index: Some(index as u64), + }; + self.eth_api + .tx_resp_builder() + .fill(tx.clone().with_signer(*signer), tx_info) + .ok() + } else { + None + } + }) + .collect(); + Ok(Some(system_txs)) + } else { + Ok(None) + } + } +} + pub struct HlNodeFilterHttp { filter: Arc>, provider: Arc, @@ -146,8 +229,9 @@ impl HlNodeFilterWs { } #[async_trait] -impl EthPubSubApiServer> - for HlNodeFilterWs +impl EthPubSubApiServer> for HlNodeFilterWs +where + jsonrpsee_types::error::ErrorObject<'static>: From<::Error>, { async fn subscribe( &self, @@ -473,5 +557,9 @@ where ctx.modules.replace_configured( HlNodeBlockFilterHttp::new(Arc::new(ctx.registry.eth_api().clone())).into_rpc(), )?; + + ctx.modules + .merge_configured(HlSystemTransactionExt::new(ctx.registry.eth_api().clone()).into_rpc())?; + Ok(()) }