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
9 changes: 9 additions & 0 deletions prdoc/pr_9878.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
title: 'pallet-revive: add custom addr recovery logic in `ReceiptExtractor`'
doc:
- audience: Node Dev
description: |-
Add ability to customize pallet-revive-eth-rpc's `ReceiptExtractor` ethereum address recovery logic, used when parsing through blocks' transactions.

crates:
- name: pallet-revive-eth-rpc
bump: minor
3 changes: 2 additions & 1 deletion substrate/frame/revive/rpc/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ fn build_client(

let receipt_extractor = ReceiptExtractor::new(
api.clone(),
earliest_receipt_block).await?;
earliest_receipt_block,
).await?;

let receipt_provider = ReceiptProvider::new(
pool,
Expand Down
44 changes: 40 additions & 4 deletions substrate/frame/revive/rpc/src/receipt_extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
transaction_payment::events::TransactionFeePaid,
SrcChainConfig,
},
ClientError, LOG_TARGET,
ClientError, H160, LOG_TARGET,
};
use futures::{stream, StreamExt};
use pallet_revive::{
Expand All @@ -37,6 +37,9 @@ use subxt::OnlineClient;
type FetchGasPriceFn = Arc<
dyn Fn(H256) -> Pin<Box<dyn Future<Output = Result<U256, ClientError>> + Send>> + Send + Sync,
>;

type RecoverEthAddressFn = Arc<dyn Fn(&TransactionSigned) -> Result<H160, ()> + Send + Sync>;

/// Utility to extract receipts from extrinsics.
#[derive(Clone)]
pub struct ReceiptExtractor {
Expand All @@ -48,6 +51,9 @@ pub struct ReceiptExtractor {

/// Earliest block number to consider when searching for transaction receipts.
earliest_receipt_block: Option<SubstrateBlockNumber>,

/// Recover the ethereum address from a transaction signature.
recover_eth_address: RecoverEthAddressFn,
}

/// Fetch the native_to_eth_ratio
Expand All @@ -66,6 +72,24 @@ impl ReceiptExtractor {
pub async fn new(
api: OnlineClient<SrcChainConfig>,
earliest_receipt_block: Option<SubstrateBlockNumber>,
) -> Result<Self, ClientError> {
Self::new_with_custom_address_recovery(
api,
earliest_receipt_block,
Arc::new(|signed_tx: &TransactionSigned| signed_tx.recover_eth_address()),
)
.await
}

/// Create a new `ReceiptExtractor` with the given native to eth ratio.
///
/// Specify also a custom Ethereum address recovery logic.
/// Use `ReceiptExtractor::new` if the default Ethereum address recovery
/// logic ([`TransactionSigned::recover_eth_address`] based) is enough.
pub async fn new_with_custom_address_recovery(
api: OnlineClient<SrcChainConfig>,
earliest_receipt_block: Option<SubstrateBlockNumber>,
recover_eth_address_fn: RecoverEthAddressFn,
) -> Result<Self, ClientError> {
let native_to_eth_ratio = native_to_eth_ratio(&api).await?;

Expand All @@ -80,15 +104,27 @@ impl ReceiptExtractor {
Box::pin(fut) as Pin<Box<_>>
});

Ok(Self { native_to_eth_ratio, fetch_gas_price, earliest_receipt_block })
Ok(Self {
native_to_eth_ratio,
fetch_gas_price,
earliest_receipt_block,
recover_eth_address: recover_eth_address_fn,
})
}

#[cfg(test)]
pub fn new_mock() -> Self {
let fetch_gas_price =
Arc::new(|_| Box::pin(std::future::ready(Ok(U256::from(1000)))) as Pin<Box<_>>);

Self { native_to_eth_ratio: 1_000_000, fetch_gas_price, earliest_receipt_block: None }
Self {
native_to_eth_ratio: 1_000_000,
fetch_gas_price,
earliest_receipt_block: None,
recover_eth_address: Arc::new(|signed_tx: &TransactionSigned| {
signed_tx.recover_eth_address()
}),
}
}

/// Extract a [`TransactionSigned`] and a [`ReceiptInfo`] from an extrinsic.
Expand Down Expand Up @@ -116,7 +152,7 @@ impl ReceiptExtractor {

let signed_tx =
TransactionSigned::decode(&call.payload).map_err(|_| ClientError::TxDecodingFailed)?;
let from = signed_tx.recover_eth_address().map_err(|_| {
let from = (self.recover_eth_address)(&signed_tx).map_err(|_| {
log::error!(target: LOG_TARGET, "Failed to recover eth address from signed tx");
ClientError::RecoverEthAddressFailed
})?;
Expand Down
Loading