Fix: high load RPC putting node in a broken state: avoid running blocking tasks within blocking tasks (#4461)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
swbartosz
2023-09-03 15:16:38 +01:00
committed by GitHub
parent acedc8cf4c
commit e8f2a56f40
3 changed files with 36 additions and 38 deletions

View File

@ -47,8 +47,12 @@ where
/// Estimate gas needed for execution of the `request` at the [BlockId]. /// Estimate gas needed for execution of the `request` at the [BlockId].
pub async fn estimate_gas_at(&self, request: CallRequest, at: BlockId) -> EthResult<U256> { pub async fn estimate_gas_at(&self, request: CallRequest, at: BlockId) -> EthResult<U256> {
let (cfg, block_env, at) = self.evm_env_at(at).await?; let (cfg, block_env, at) = self.evm_env_at(at).await?;
let state = self.state_at(at)?;
self.estimate_gas_with(cfg, block_env, request, state) self.on_blocking_task(|this| async move {
let state = this.state_at(at)?;
this.estimate_gas_with(cfg, block_env, request, state)
})
.await
} }
/// Executes the call request (`eth_call`) and returns the output /// Executes the call request (`eth_call`) and returns the output

View File

@ -236,14 +236,7 @@ where
) -> Result<Bytes> { ) -> Result<Bytes> {
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call"); trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
Ok(self Ok(self
.on_blocking_task(|this| async move { .call(request, block_number, EvmOverrides::new(state_overrides, block_overrides))
this.call(
request,
block_number,
EvmOverrides::new(state_overrides, block_overrides),
)
.await
})
.await?) .await?)
} }
@ -265,15 +258,11 @@ where
block_number: Option<BlockId>, block_number: Option<BlockId>,
) -> Result<AccessListWithGasUsed> { ) -> Result<AccessListWithGasUsed> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList"); trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
Ok(self let block_id = block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest));
.on_blocking_task(|this| async move { let access_list = self.create_access_list_at(request.clone(), block_number).await?;
let block_id = block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)); request.access_list = Some(access_list.clone());
let access_list = this.create_access_list_at(request.clone(), block_number).await?; let gas_used = self.estimate_gas_at(request, block_id).await?;
request.access_list = Some(access_list.clone()); Ok(AccessListWithGasUsed { access_list, gas_used })
let gas_used = this.estimate_gas_at(request, block_id).await?;
Ok(AccessListWithGasUsed { access_list, gas_used })
})
.await?)
} }
/// Handler for: `eth_estimateGas` /// Handler for: `eth_estimateGas`
@ -284,13 +273,10 @@ where
) -> Result<U256> { ) -> Result<U256> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas"); trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
Ok(self Ok(self
.on_blocking_task(|this| async move { .estimate_gas_at(
this.estimate_gas_at( request,
request, block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)),
block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)), )
)
.await
})
.await?) .await?)
} }

View File

@ -400,20 +400,28 @@ where
} }
async fn transaction_receipt(&self, hash: H256) -> EthResult<Option<TransactionReceipt>> { async fn transaction_receipt(&self, hash: H256) -> EthResult<Option<TransactionReceipt>> {
self.on_blocking_task(|this| async move { let result = self
let (tx, meta) = match this.provider().transaction_by_hash_with_meta(hash)? { .on_blocking_task(|this| async move {
Some((tx, meta)) => (tx, meta), let (tx, meta) = match this.provider().transaction_by_hash_with_meta(hash)? {
None => return Ok(None), Some((tx, meta)) => (tx, meta),
}; None => return Ok(None),
};
let receipt = match this.provider().receipt_by_hash(hash)? { let receipt = match this.provider().receipt_by_hash(hash)? {
Some(recpt) => recpt, Some(recpt) => recpt,
None => return Ok(None), None => return Ok(None),
}; };
this.build_transaction_receipt(tx, meta, receipt).await.map(Some) Ok(Some((tx, meta, receipt)))
}) })
.await .await?;
let (tx, meta, receipt) = match result {
Some((tx, meta, receipt)) => (tx, meta, receipt),
None => return Ok(None),
};
self.build_transaction_receipt(tx, meta, receipt).await.map(Some)
} }
async fn send_raw_transaction(&self, tx: Bytes) -> EthResult<H256> { async fn send_raw_transaction(&self, tx: Bytes) -> EthResult<H256> {