diff --git a/chain/ethereum/src/ethereum_adapter.rs b/chain/ethereum/src/ethereum_adapter.rs index 9c85f0ac551..d30f578b773 100644 --- a/chain/ethereum/src/ethereum_adapter.rs +++ b/chain/ethereum/src/ethereum_adapter.rs @@ -2315,13 +2315,31 @@ async fn batch_get_transaction_receipts( Ok(results) } +/// Fetch block receipts by hash, sending the block hash as a plain string +/// param (`["0x.."]`) rather than alloy's default EIP-1898 object +/// (`[{"blockHash":".."}]`). +/// +/// `eth_getBlockReceipts` accepts both forms on most clients, but some (e.g. +/// taraxa-node) only accept the plain-string hash and reject the object with +/// `INVALID_PARAMS`. The string form is accepted by all known implementations, +/// so we always use it; alloy's typed `get_block_receipts` would always emit +/// the object form. See issue #5835. +async fn get_block_receipts_by_hash( + alloy: &AlloyProvider, + block_hash: B256, +) -> Result>, RpcError> { + alloy + .client() + .request("eth_getBlockReceipts", (block_hash,)) + .await +} + pub(crate) async fn check_block_receipt_support( alloy: Arc, block_hash: B256, supports_eip_1898: bool, call_only: bool, ) -> Result<(), Error> { - use alloy::rpc::types::BlockId; if call_only { return Err(anyhow!("Provider is call-only")); } @@ -2331,7 +2349,7 @@ pub(crate) async fn check_block_receipt_support( } // Fetch block receipts from the provider for the latest block. - let block_receipts_result = alloy.get_block_receipts(BlockId::from(block_hash)).await; + let block_receipts_result = get_block_receipts_by_hash(&alloy, block_hash).await; // Determine if the provider supports block receipts based on the fetched result. match block_receipts_result { @@ -2406,7 +2424,6 @@ async fn fetch_block_receipts_with_retry( logger: ProviderLogger, settings: &ChainSettings, ) -> Result>, IngestorError> { - use graph::prelude::alloy::rpc::types::BlockId; let retry_log_message = format!("eth_getBlockReceipts RPC call for block {:?}", block_hash); // Perform the retry operation @@ -2414,7 +2431,10 @@ async fn fetch_block_receipts_with_retry( .redact_log_urls(true) .limit(settings.request_retries) .timeout_secs(settings.json_rpc_timeout.as_secs()) - .run(move || alloy.get_block_receipts(BlockId::from(block_hash)).boxed()) + .run(move || { + let alloy = alloy.clone(); + async move { get_block_receipts_by_hash(&alloy, block_hash).await }.boxed() + }) .await .map_err(|_timeout| -> IngestorError { anyhow!(block_hash).into() })?;