diff --git a/prdoc/pr_10220.prdoc b/prdoc/pr_10220.prdoc new file mode 100644 index 0000000000000..c554dd4634b2b --- /dev/null +++ b/prdoc/pr_10220.prdoc @@ -0,0 +1,13 @@ +title: Notify when there is a new best block +doc: +- audience: Runtime Dev + description: |- + # Description + + Modify the tx_notifier to send the block hash to the subscribers instead of all transactions hashes. + Modify the send_raw_transaction to look for the transaction hash in the transactions field of the evm block. +crates: +- name: pallet-revive-eth-rpc + bump: major +- name: pallet-revive + bump: minor diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 75b49495cabc1..66d6ae09d47b4 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -134,6 +134,8 @@ pub enum ClientError { const LOG_TARGET: &str = "eth-rpc::client"; const REVERT_CODE: i32 = 3; + +const NOTIFIER_CAPACITY: usize = 16; impl From for ErrorObjectOwned { fn from(err: ClientError) -> Self { match err { @@ -172,9 +174,8 @@ pub struct Client { max_block_weight: Weight, /// Whether the node has automine enabled. automine: bool, - /// A notifier, that informs subscribers of new transaction hashes that are included in a - /// block, when automine is enabled. - tx_notifier: Option>, + /// A notifier, that informs subscribers of new best blocks. + block_notifier: Option>, /// A lock to ensure only one subscription can perform write operations at a time. subscription_lock: Arc>, } @@ -247,13 +248,19 @@ impl Client { chain_id, max_block_weight, automine, - tx_notifier: automine.then(|| tokio::sync::broadcast::channel::(10).0), + block_notifier: automine + .then(|| tokio::sync::broadcast::channel::(NOTIFIER_CAPACITY).0), subscription_lock: Arc::new(Mutex::new(())), }; Ok(client) } + /// Creates a block notifier instance. + pub fn create_block_notifier(&mut self) { + self.block_notifier = Some(tokio::sync::broadcast::channel::(NOTIFIER_CAPACITY).0); + } + /// Subscribe to past blocks executing the callback for each block in `range`. async fn subscribe_past_blocks( &self, @@ -349,7 +356,8 @@ impl Client { ) -> Result<(), ClientError> { log::info!(target: LOG_TARGET, "🔌 Subscribing to new blocks ({subscription_type:?})"); self.subscribe_new_blocks(subscription_type, |block| async { - let evm_block = self.runtime_api(block.hash()).eth_block().await?; + let hash = block.hash(); + let evm_block = self.runtime_api(hash).eth_block().await?; let (_, receipts): (Vec<_>, Vec<_>) = self .receipt_provider .insert_block_receipts(&block, &evm_block.hash) @@ -361,11 +369,10 @@ impl Client { self.fee_history_provider.update_fee_history(&evm_block, &receipts).await; // Only broadcast for best blocks to avoid duplicate notifications. - match (subscription_type, &self.tx_notifier) { - (SubscriptionType::BestBlocks, Some(sender)) if sender.receiver_count() > 0 => - for receipt in &receipts { - let _ = sender.send(receipt.transaction_hash); - }, + match (subscription_type, &self.block_notifier) { + (SubscriptionType::BestBlocks, Some(sender)) if sender.receiver_count() > 0 => { + let _ = sender.send(hash); + }, _ => {}, } Ok(()) @@ -742,9 +749,9 @@ impl Client { self.max_block_weight } - /// Get the block notifier, if automine is enabled. - pub fn tx_notifier(&self) -> Option> { - self.tx_notifier.clone() + /// Get the block notifier, if automine is enabled or Self::create_block_notifier was called. + pub fn block_notifier(&self) -> Option> { + self.block_notifier.clone() } /// Get the logs matching the given filter. diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index d742ad937f3b9..6dc1f397fefaf 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -169,7 +169,7 @@ impl EthRpcServer for EthRpcServerImpl { let call = subxt_client::tx().revive().eth_transact(transaction.0); // Subscribe to new block only when automine is enabled. - let receiver = self.client.tx_notifier().map(|sender| sender.subscribe()); + let receiver = self.client.block_notifier().map(|sender| sender.subscribe()); // Submit the transaction let substrate_hash = self.client.submit(call).await.map_err(|err| { @@ -183,8 +183,16 @@ impl EthRpcServer for EthRpcServerImpl { if let Some(mut receiver) = receiver { if let Err(err) = tokio::time::timeout(Duration::from_millis(500), async { loop { - if let Ok(mined_hash) = receiver.recv().await { - if mined_hash == hash { + if let Ok(block_hash) = receiver.recv().await { + let Ok(Some(block)) = self.client.block_by_hash(&block_hash).await else { + log::debug!(target: LOG_TARGET, "Could not find the block with the received hash: {hash:?}."); + continue + }; + let Some(evm_block) = self.client.evm_block(block, false).await else { + log::debug!(target: LOG_TARGET, "Failed to get the EVM block for substrate block with hash: {hash:?}"); + continue + }; + if evm_block.transactions.contains_tx(hash) { log::debug!(target: LOG_TARGET, "{hash:} was included in a block"); break; } diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs index 11807ea438b76..c3260b3877586 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -540,6 +540,14 @@ impl HashesOrTransactionInfos { pub fn is_empty(&self) -> bool { self.len() == 0 } + + pub fn contains_tx(&self, hash: H256) -> bool { + match self { + HashesOrTransactionInfos::Hashes(hashes) => hashes.iter().any(|h256| *h256 == hash), + HashesOrTransactionInfos::TransactionInfos(transaction_infos) => + transaction_infos.iter().any(|ti| ti.hash == hash), + } + } } /// log