Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions prdoc/pr_9914.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: ' Wait for transaction receipt if instant seal is enabled'
doc:
- audience: Runtime Dev
description: "Fixes https://github.com/paritytech/contract-issues/issues/165\n\n\
The main changes in this PR are:\n\n1. Add a new API to revive-dev-node to check\
\ whether the node has instant seal enabled.\n2. Add a new debug API to eth-rpc\
\ to check whether the node has instant seal enabled. (optional)\n3. Query and\
\ cache the node\u2019s instant seal status during eth-rpc initialization.\n4.\
\ If instant seal is enabled, wait for the transaction receipt to be available"
crates:
- name: pallet-revive-eth-rpc
bump: patch
2 changes: 1 addition & 1 deletion substrate/frame/revive/dev-node/node/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use polkadot_sdk::{sc_cli::RunCmd, *};

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub enum Consensus {
ManualSeal(u64),
InstantSeal,
Expand Down
38 changes: 36 additions & 2 deletions substrate/frame/revive/dev-node/node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

#![warn(missing_docs)]

use jsonrpsee::RpcModule;
use crate::cli::Consensus;
use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule};
use polkadot_sdk::{
sc_transaction_pool_api::TransactionPool,
sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata},
Expand All @@ -37,6 +38,38 @@ pub struct FullDeps<C, P> {
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// The consensus type of the node.
pub consensus: Consensus,
}

/// AutoMine JSON-RPC api.
Comment thread
marian-radu marked this conversation as resolved.
/// Automine is a feature of the Hardhat Network where a new block is automatically mined after each
/// transaction.
#[rpc(server, client)]
pub trait AutoMineRpc {
/// API to get the automine status.
#[method(name = "getAutomine")]
fn get_automine(&self) -> RpcResult<bool>;
}

/// Implementation of the AutoMine RPC api.
pub struct AutoMineRpcImpl {
/// Whether the node is running in auto-mine mode.
is_auto_mine: bool,
}

impl AutoMineRpcImpl {
/// Create new `AutoMineRpcImpl` instance.
pub fn new(consensus: Consensus) -> Self {
Self { is_auto_mine: matches!(consensus, Consensus::InstantSeal) }
}
}

impl AutoMineRpcServer for AutoMineRpcImpl {
/// Returns `true` if block production is set to `instant`.
fn get_automine(&self) -> RpcResult<bool> {
Comment thread
pgherveou marked this conversation as resolved.
Ok(self.is_auto_mine)
}
}

#[docify::export]
Expand All @@ -58,8 +91,9 @@ where
{
use polkadot_sdk::substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcModule::new(());
let FullDeps { client, pool } = deps;
let FullDeps { client, pool, consensus } = deps;

module.merge(AutoMineRpcImpl::new(consensus).into_rpc())?;
module.merge(System::new(client.clone(), pool.clone()).into_rpc())?;

Ok(module)
Expand Down
3 changes: 2 additions & 1 deletion substrate/frame/revive/dev-node/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ pub fn new_full<Network: sc_network::NetworkBackend<Block, <Block as BlockT>::Ha
let pool = transaction_pool.clone();

Box::new(move |_| {
let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() };
let deps =
crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), consensus };
crate::rpc::create_full(deps).map_err(Into::into)
})
};
Expand Down
7 changes: 7 additions & 0 deletions substrate/frame/revive/rpc/src/apis/debug_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub trait DebugRpc {
block: BlockNumberOrTagOrHash,
tracer_config: TracerConfig,
) -> RpcResult<Trace>;

#[method(name = "debug_getAutomine")]
async fn get_automine(&self) -> RpcResult<bool>;
}

pub struct DebugRpcServerImpl {
Expand Down Expand Up @@ -115,4 +118,8 @@ impl DebugRpcServer for DebugRpcServerImpl {
let TracerConfig { config, timeout } = tracer_config;
with_timeout(timeout, self.client.trace_call(transaction, block, config)).await
}

async fn get_automine(&self) -> RpcResult<bool> {
sc_service::Result::Ok(self.client.get_automine().await)
}
}
61 changes: 53 additions & 8 deletions substrate/frame/revive/rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
mod runtime_api;
mod storage_api;

use runtime_api::RuntimeApi;
use storage_api::StorageApi;

use crate::{
subxt_client::{self, revive::calls::types::EthTransact, SrcChainConfig},
BlockInfoProvider, BlockTag, FeeHistoryProvider, ReceiptProvider, SubxtBlockInfoProvider,
Expand All @@ -37,9 +34,11 @@ use pallet_revive::{
},
EthTransactError,
};
use runtime_api::RuntimeApi;
use sp_runtime::traits::Block as BlockT;
use sp_weights::Weight;
use std::{ops::Range, sync::Arc, time::Duration};
use storage_api::StorageApi;
use subxt::{
backend::{
legacy::{rpc_methods::SystemHealth, LegacyRpcMethods},
Expand Down Expand Up @@ -70,7 +69,7 @@ pub type SubstrateBlockHash = HashFor<SrcChainConfig>;
pub type Balance = u128;

/// The subscription type used to listen to new blocks.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SubscriptionType {
/// Subscribe to best blocks.
BestBlocks,
Expand Down Expand Up @@ -160,6 +159,11 @@ pub struct Client {
fee_history_provider: FeeHistoryProvider,
chain_id: u64,
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<tokio::sync::broadcast::Sender<H256>>,
}

/// Fetch the chain ID from the substrate chain.
Expand All @@ -176,6 +180,17 @@ async fn max_block_weight(api: &OnlineClient<SrcChainConfig>) -> Result<Weight,
Ok(max_block.0)
}

/// Get the automine status from the node.
async fn get_automine(rpc_client: &RpcClient) -> bool {
match rpc_client.request::<bool>("getAutomine", rpc_params![]).await {
Ok(val) => val,
Err(err) => {
log::info!(target: LOG_TARGET, "Node does not have getAutomine RPC. Defaulting to automine=false. error: {err:?}");
false
},
}
}

/// Extract the block timestamp.
async fn extract_block_timestamp(block: &SubstrateBlock) -> Option<u64> {
let extrinsics = block.extrinsics().await.ok()?;
Expand Down Expand Up @@ -214,10 +229,12 @@ impl Client {
block_provider: SubxtBlockInfoProvider,
receipt_provider: ReceiptProvider,
) -> Result<Self, ClientError> {
let (chain_id, max_block_weight) =
tokio::try_join!(chain_id(&api), max_block_weight(&api))?;
let (chain_id, max_block_weight, automine) =
tokio::try_join!(chain_id(&api), max_block_weight(&api), async {
Ok(get_automine(&rpc_client).await)
},)?;

Ok(Self {
let client = Self {
api,
rpc_client,
rpc,
Expand All @@ -226,7 +243,11 @@ impl Client {
fee_history_provider: FeeHistoryProvider::default(),
chain_id,
max_block_weight,
})
automine,
tx_notifier: automine.then(|| tokio::sync::broadcast::channel::<H256>(10).0),
};

Ok(client)
}

/// Subscribe to past blocks executing the callback for each block in `range`.
Expand Down Expand Up @@ -329,6 +350,15 @@ impl Client {
self.block_provider.update_latest(block, subscription_type).await;

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);
},
_ => {},
}
Ok(())
})
.await
Expand Down Expand Up @@ -682,6 +712,11 @@ impl Client {
self.max_block_weight
}

/// Get the block notifier, if automine is enabled.
pub fn tx_notifier(&self) -> Option<tokio::sync::broadcast::Sender<H256>> {
self.tx_notifier.clone()
}

/// Get the logs matching the given filter.
pub async fn logs(&self, filter: Option<Filter>) -> Result<Vec<Log>, ClientError> {
let logs =
Expand All @@ -703,4 +738,14 @@ impl Client {
.fee_history(block_count, latest_block.number(), reward_percentiles)
.await
}

/// Check if automine is enabled.
pub fn is_automine(&self) -> bool {
self.automine
}

/// Get the automine status from the node.
pub async fn get_automine(&self) -> bool {
get_automine(&self.rpc_client).await
}
}
24 changes: 24 additions & 0 deletions substrate/frame/revive/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use pallet_revive::evm::*;
use sp_arithmetic::Permill;
use sp_core::{keccak_256, H160, H256, U256};
use thiserror::Error;
use tokio::time::Duration;

pub mod cli;
pub mod client;
Expand Down Expand Up @@ -164,11 +165,34 @@ impl EthRpcServer for EthRpcServerImpl {
async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult<H256> {
let hash = H256(keccak_256(&transaction.0));
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());

// Submit the transaction
self.client.submit(call).await.map_err(|err| {
log::debug!(target: LOG_TARGET, "submit call failed: {err:?}");
err
})?;

// Wait for the transaction to be included in a block if automine is enabled
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 {
log::debug!(target: LOG_TARGET, "{hash:} was included in a block");
break;
}
}
}
})
.await
{
log::debug!(target: LOG_TARGET, "timeout waiting for new block: {err:?}");
}
}

log::debug!(target: LOG_TARGET, "send_raw_transaction hash: {hash:?}");
Ok(hash)
}
Expand Down
Loading