ethers_providers/middleware.rs
1use async_trait::async_trait;
2use auto_impl::auto_impl;
3use ethers_core::types::{
4 transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
5 *,
6};
7use futures_util::future::join_all;
8use serde::{de::DeserializeOwned, Serialize};
9use std::fmt::Debug;
10use url::Url;
11
12use crate::{
13 erc, EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, JsonRpcClient, LogQuery,
14 MiddlewareError, NodeInfo, PeerInfo, PendingTransaction, Provider, ProviderError, PubsubClient,
15 SubscriptionStream,
16};
17
18/// A middleware allows customizing requests send and received from an ethereum node.
19///
20/// Writing a middleware is as simple as:
21/// 1. implementing the [`inner`](crate::Middleware::inner) method to point to the next layer in the
22/// "middleware onion", 2. implementing the
23/// [`MiddlewareError`](crate::MiddlewareError) trait on your middleware's
24/// error type 3. implementing any of the methods you want to override
25///
26/// ```
27/// use ethers_providers::{Middleware, MiddlewareError};
28/// use ethers_core::types::{U64, TransactionRequest, U256, transaction::eip2718::TypedTransaction, BlockId};
29/// use thiserror::Error;
30/// use async_trait::async_trait;
31///
32/// #[derive(Debug)]
33/// struct MyMiddleware<M>(M);
34///
35/// #[derive(Error, Debug)]
36/// pub enum MyError<M: Middleware> {
37/// #[error("{0}")]
38/// MiddlewareError(M::Error),
39///
40/// // Add your middleware's specific errors here
41/// }
42///
43/// impl<M: Middleware> MiddlewareError for MyError<M> {
44/// type Inner = M::Error;
45///
46/// fn from_err(src: M::Error) -> MyError<M> {
47/// MyError::MiddlewareError(src)
48/// }
49///
50/// fn as_inner(&self) -> Option<&Self::Inner> {
51/// match self {
52/// MyError::MiddlewareError(e) => Some(e),
53/// _ => None,
54/// }
55/// }
56/// }
57///
58/// #[async_trait]
59/// impl<M> Middleware for MyMiddleware<M>
60/// where
61/// M: Middleware,
62/// {
63/// type Error = MyError<M>;
64/// type Provider = M::Provider;
65/// type Inner = M;
66///
67/// fn inner(&self) -> &M {
68/// &self.0
69/// }
70///
71/// /// Overrides the default `get_block_number` method to always return 0
72/// async fn get_block_number(&self) -> Result<U64, Self::Error> {
73/// Ok(U64::zero())
74/// }
75///
76/// /// Overrides the default `estimate_gas` method to log that it was called,
77/// /// before forwarding the call to the next layer.
78/// async fn estimate_gas(&self, tx: &TypedTransaction, block: Option<BlockId>) -> Result<U256, Self::Error> {
79/// println!("Estimating gas...");
80/// self.inner().estimate_gas(tx, block).await.map_err(MiddlewareError::from_err)
81/// }
82/// }
83/// ```
84#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
85#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
86#[auto_impl(&, Box, Arc)]
87pub trait Middleware: Sync + Send + Debug {
88 /// Error type returned by most operations
89 type Error: MiddlewareError<Inner = <<Self as Middleware>::Inner as Middleware>::Error>;
90 /// The JSON-RPC client type at the bottom of the stack
91 type Provider: JsonRpcClient;
92 /// The next-lower middleware in the middleware stack
93 type Inner: Middleware<Provider = Self::Provider>;
94
95 /// Get a reference to the next-lower middleware in the middleware stack
96 fn inner(&self) -> &Self::Inner;
97
98 /// Convert a provider error into the associated error type by successively
99 /// converting it to every intermediate middleware error
100 fn convert_err(p: ProviderError) -> Self::Error {
101 Self::Error::from_provider_err(p)
102 }
103
104 /// The HTTP or Websocket provider.
105 fn provider(&self) -> &Provider<Self::Provider> {
106 self.inner().provider()
107 }
108
109 /// Return the default sender (if any). This will typically be the
110 /// connected node's first address, or the address of a Signer in a lower
111 /// middleware stack
112 fn default_sender(&self) -> Option<Address> {
113 self.inner().default_sender()
114 }
115
116 /// Returns the current client version using the `web3_clientVersion` RPC.
117 async fn client_version(&self) -> Result<String, Self::Error> {
118 self.inner().client_version().await.map_err(MiddlewareError::from_err)
119 }
120
121 /// Fill necessary details of a transaction for dispatch
122 ///
123 /// This function is defined on providers to behave as follows:
124 /// 1. populate the `from` field with the default sender
125 /// 2. resolve any ENS names in the tx `to` field
126 /// 3. Estimate gas usage
127 /// 4. Poll and set legacy or 1559 gas prices
128 /// 5. Set the chain_id with the provider's, if not already set
129 ///
130 /// It does NOT set the nonce by default.
131 ///
132 /// Middleware are encouraged to override any values _before_ delegating
133 /// to the inner implementation AND/OR modify the values provided by the
134 /// default implementation _after_ delegating.
135 ///
136 /// E.g. a middleware wanting to double gas prices should consider doing so
137 /// _after_ delegating and allowing the default implementation to poll gas.
138 async fn fill_transaction(
139 &self,
140 tx: &mut TypedTransaction,
141 block: Option<BlockId>,
142 ) -> Result<(), Self::Error> {
143 self.inner().fill_transaction(tx, block).await.map_err(MiddlewareError::from_err)
144 }
145
146 /// Get the block number
147 async fn get_block_number(&self) -> Result<U64, Self::Error> {
148 self.inner().get_block_number().await.map_err(MiddlewareError::from_err)
149 }
150
151 /// Get the block header by number or hash
152 async fn get_header<T: Into<BlockId> + Send + Sync>(
153 &self,
154 block_hash_or_number: T,
155 ) -> Result<Option<Block<Transaction>>, Self::Error> {
156 self.inner().get_header(block_hash_or_number).await.map_err(MiddlewareError::from_err)
157 }
158
159 /// Sends the transaction to the entire Ethereum network and returns the
160 /// transaction's hash. This will consume gas from the account that signed
161 /// the transaction. This call will fail if no signer is available, and the
162 /// RPC node does not have an unlocked accounts
163 async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
164 &self,
165 tx: T,
166 block: Option<BlockId>,
167 ) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
168 self.inner().send_transaction(tx, block).await.map_err(MiddlewareError::from_err)
169 }
170
171 /// Send a transaction with a simple escalation policy.
172 ///
173 /// `policy` should be a boxed function that maps `original_gas_price`
174 /// and `number_of_previous_escalations` -> `new_gas_price`.
175 ///
176 /// e.g. `Box::new(|start, escalation_index| start * 1250.pow(escalations) /
177 /// 1000.pow(escalations))`
178 async fn send_escalating<'a>(
179 &'a self,
180 tx: &TypedTransaction,
181 escalations: usize,
182 policy: EscalationPolicy,
183 ) -> Result<EscalatingPending<'a, Self::Provider>, Self::Error> {
184 let mut original = tx.clone();
185 self.fill_transaction(&mut original, None).await?;
186
187 // set the nonce, if no nonce is found
188 if original.nonce().is_none() {
189 let nonce =
190 self.get_transaction_count(tx.from().copied().unwrap_or_default(), None).await?;
191 original.set_nonce(nonce);
192 }
193
194 let gas_price = original.gas_price().expect("filled");
195 let sign_futs: Vec<_> = (0..escalations)
196 .map(|i| {
197 let new_price = policy(gas_price, i);
198 let mut r = original.clone();
199 r.set_gas_price(new_price);
200 r
201 })
202 .map(|req| async move {
203 self.sign_transaction(&req, self.default_sender().unwrap_or_default())
204 .await
205 .map(|sig| req.rlp_signed(&sig))
206 })
207 .collect();
208
209 // we reverse for convenience. Ensuring that we can always just
210 // `pop()` the next tx off the back later
211 let mut signed = join_all(sign_futs).await.into_iter().collect::<Result<Vec<_>, _>>()?;
212 signed.reverse();
213
214 Ok(EscalatingPending::new(self.provider(), signed))
215 }
216
217 ////// Ethereum Naming Service
218 // The Ethereum Naming Service (ENS) allows easy to remember and use names to
219 // be assigned to Ethereum addresses. Any provider operation which takes an address
220 // may also take an ENS name.
221 //
222 // ENS also provides the ability for a reverse lookup, which determines the name for an address
223 // if it has been configured.
224
225 /// Returns the address that the `ens_name` resolves to (or None if not configured).
226 ///
227 /// # Panics
228 ///
229 /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
230 /// an address. This should theoretically never happen.
231 async fn resolve_name(&self, ens_name: &str) -> Result<Address, Self::Error> {
232 self.inner().resolve_name(ens_name).await.map_err(MiddlewareError::from_err)
233 }
234
235 /// Returns the ENS name the `address` resolves to (or None if not configured).
236 ///
237 /// # Panics
238 ///
239 /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
240 /// a string. This should theoretically never happen.
241 async fn lookup_address(&self, address: Address) -> Result<String, Self::Error> {
242 self.inner().lookup_address(address).await.map_err(MiddlewareError::from_err)
243 }
244
245 /// Returns the avatar HTTP link of the avatar that the `ens_name` resolves to (or None
246 /// if not configured)
247 ///
248 /// # Examples
249 ///
250 /// ```no_run
251 /// # use ethers_providers::{Provider, Http, Middleware};
252 /// # async fn foo(provider: Provider<Http>) -> Result<(), Box<dyn std::error::Error>> {
253 /// let avatar = provider.resolve_avatar("parishilton.eth").await?;
254 /// assert_eq!(avatar.to_string(), "https://i.imgur.com/YW3Hzph.jpg");
255 /// # Ok(()) }
256 /// ```
257 ///
258 /// # Panics
259 ///
260 /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
261 /// a string. This should theoretically never happen.
262 async fn resolve_avatar(&self, ens_name: &str) -> Result<Url, Self::Error> {
263 self.inner().resolve_avatar(ens_name).await.map_err(MiddlewareError::from_err)
264 }
265
266 /// Returns the URL (not necesserily HTTP) of the image behind a token.
267 ///
268 /// # Example
269 /// ```no_run
270 /// # use ethers_providers::{Provider, Http, Middleware};
271 /// use ethers_providers::erc::ERCNFT;
272 /// # async fn foo(provider: Provider<Http>) -> Result<(), Box<dyn std::error::Error>> {
273 /// let token = "erc721:0xc92ceddfb8dd984a89fb494c376f9a48b999aafc/9018".parse()?;
274 /// let token_image = provider.resolve_nft(token).await?;
275 /// assert_eq!(
276 /// token_image.to_string(),
277 /// "https://creature.mypinata.cloud/ipfs/QmNwj3aUzXfG4twV3no7hJRYxLLAWNPk6RrfQaqJ6nVJFa/9018.jpg"
278 /// );
279 /// # Ok(()) }
280 /// ```
281 ///
282 /// # Panics
283 ///
284 /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
285 /// a string. This should theoretically never happen.
286 async fn resolve_nft(&self, token: erc::ERCNFT) -> Result<Url, Self::Error> {
287 self.inner().resolve_nft(token).await.map_err(MiddlewareError::from_err)
288 }
289
290 /// Fetch a field for the `ens_name` (no None if not configured).
291 ///
292 /// # Panics
293 ///
294 /// If the bytes returned from the ENS registrar/resolver cannot be interpreted as
295 /// a string. This should theoretically never happen.
296 async fn resolve_field(&self, ens_name: &str, field: &str) -> Result<String, Self::Error> {
297 self.inner().resolve_field(ens_name, field).await.map_err(MiddlewareError::from_err)
298 }
299
300 /// Gets the block at `block_hash_or_number` (transaction hashes only)
301 async fn get_block<T: Into<BlockId> + Send + Sync>(
302 &self,
303 block_hash_or_number: T,
304 ) -> Result<Option<Block<TxHash>>, Self::Error> {
305 self.inner().get_block(block_hash_or_number).await.map_err(MiddlewareError::from_err)
306 }
307
308 /// Gets the block at `block_hash_or_number` (full transactions included)
309 async fn get_block_with_txs<T: Into<BlockId> + Send + Sync>(
310 &self,
311 block_hash_or_number: T,
312 ) -> Result<Option<Block<Transaction>>, Self::Error> {
313 self.inner()
314 .get_block_with_txs(block_hash_or_number)
315 .await
316 .map_err(MiddlewareError::from_err)
317 }
318
319 /// Gets the block uncle count at `block_hash_or_number`
320 async fn get_uncle_count<T: Into<BlockId> + Send + Sync>(
321 &self,
322 block_hash_or_number: T,
323 ) -> Result<U256, Self::Error> {
324 self.inner().get_uncle_count(block_hash_or_number).await.map_err(MiddlewareError::from_err)
325 }
326
327 /// Gets the block uncle at `block_hash_or_number` and `idx`
328 async fn get_uncle<T: Into<BlockId> + Send + Sync>(
329 &self,
330 block_hash_or_number: T,
331 idx: U64,
332 ) -> Result<Option<Block<H256>>, Self::Error> {
333 self.inner().get_uncle(block_hash_or_number, idx).await.map_err(MiddlewareError::from_err)
334 }
335
336 /// Returns the nonce of the address
337 async fn get_transaction_count<T: Into<NameOrAddress> + Send + Sync>(
338 &self,
339 from: T,
340 block: Option<BlockId>,
341 ) -> Result<U256, Self::Error> {
342 self.inner().get_transaction_count(from, block).await.map_err(MiddlewareError::from_err)
343 }
344
345 /// Sends a transaction to a single Ethereum node and return the estimated amount of gas
346 /// required (as a U256) to send it This is free, but only an estimate. Providing too little
347 /// gas will result in a transaction being rejected (while still consuming all provided
348 /// gas).
349 async fn estimate_gas(
350 &self,
351 tx: &TypedTransaction,
352 block: Option<BlockId>,
353 ) -> Result<U256, Self::Error> {
354 self.inner().estimate_gas(tx, block).await.map_err(MiddlewareError::from_err)
355 }
356
357 /// Sends the read-only (constant) transaction to a single Ethereum node and return the result
358 /// (as bytes) of executing it. This is free, since it does not change any state on the
359 /// blockchain.
360 async fn call(
361 &self,
362 tx: &TypedTransaction,
363 block: Option<BlockId>,
364 ) -> Result<Bytes, Self::Error> {
365 self.inner().call(tx, block).await.map_err(MiddlewareError::from_err)
366 }
367
368 /// Return current client syncing status. If IsFalse sync is over.
369 async fn syncing(&self) -> Result<SyncingStatus, Self::Error> {
370 self.inner().syncing().await.map_err(MiddlewareError::from_err)
371 }
372
373 /// Returns the currently configured chain id, a value used in replay-protected
374 /// transaction signing as introduced by EIP-155.
375 async fn get_chainid(&self) -> Result<U256, Self::Error> {
376 self.inner().get_chainid().await.map_err(MiddlewareError::from_err)
377 }
378
379 /// Returns the network version.
380 async fn get_net_version(&self) -> Result<String, Self::Error> {
381 self.inner().get_net_version().await.map_err(MiddlewareError::from_err)
382 }
383
384 /// Returns the account's balance
385 async fn get_balance<T: Into<NameOrAddress> + Send + Sync>(
386 &self,
387 from: T,
388 block: Option<BlockId>,
389 ) -> Result<U256, Self::Error> {
390 self.inner().get_balance(from, block).await.map_err(MiddlewareError::from_err)
391 }
392
393 /// Gets the transaction with `transaction_hash`
394 async fn get_transaction<T: Send + Sync + Into<TxHash>>(
395 &self,
396 transaction_hash: T,
397 ) -> Result<Option<Transaction>, Self::Error> {
398 self.inner().get_transaction(transaction_hash).await.map_err(MiddlewareError::from_err)
399 }
400
401 /// Gets the transaction with block and index
402 async fn get_transaction_by_block_and_index<T: Into<BlockId> + Send + Sync>(
403 &self,
404 block_hash_or_number: T,
405 idx: U64,
406 ) -> Result<Option<Transaction>, Self::Error> {
407 self.inner()
408 .get_transaction_by_block_and_index(block_hash_or_number, idx)
409 .await
410 .map_err(MiddlewareError::from_err)
411 }
412
413 /// Gets the transaction receipt with `transaction_hash`
414 async fn get_transaction_receipt<T: Send + Sync + Into<TxHash>>(
415 &self,
416 transaction_hash: T,
417 ) -> Result<Option<TransactionReceipt>, Self::Error> {
418 self.inner()
419 .get_transaction_receipt(transaction_hash)
420 .await
421 .map_err(MiddlewareError::from_err)
422 }
423
424 /// Returns all receipts for a block.
425 ///
426 /// Note that this uses the `eth_getBlockReceipts` RPC, which is
427 /// non-standard and currently supported by Erigon.
428 async fn get_block_receipts<T: Into<BlockNumber> + Send + Sync>(
429 &self,
430 block: T,
431 ) -> Result<Vec<TransactionReceipt>, Self::Error> {
432 self.inner().get_block_receipts(block).await.map_err(MiddlewareError::from_err)
433 }
434
435 /// Gets the current gas price as estimated by the node
436 async fn get_gas_price(&self) -> Result<U256, Self::Error> {
437 self.inner().get_gas_price().await.map_err(MiddlewareError::from_err)
438 }
439
440 /// Gets a heuristic recommendation of max fee per gas and max priority fee per gas for
441 /// EIP-1559 compatible transactions.
442 async fn estimate_eip1559_fees(
443 &self,
444 estimator: Option<fn(U256, Vec<Vec<U256>>) -> (U256, U256)>,
445 ) -> Result<(U256, U256), Self::Error> {
446 self.inner().estimate_eip1559_fees(estimator).await.map_err(MiddlewareError::from_err)
447 }
448
449 /// Gets the accounts on the node
450 async fn get_accounts(&self) -> Result<Vec<Address>, Self::Error> {
451 self.inner().get_accounts().await.map_err(MiddlewareError::from_err)
452 }
453
454 /// Send the raw RLP encoded transaction to the entire Ethereum network and returns the
455 /// transaction's hash This will consume gas from the account that signed the transaction.
456 async fn send_raw_transaction<'a>(
457 &'a self,
458 tx: Bytes,
459 ) -> Result<PendingTransaction<'a, Self::Provider>, Self::Error> {
460 self.inner().send_raw_transaction(tx).await.map_err(MiddlewareError::from_err)
461 }
462
463 /// This returns true if either the middleware stack contains a `SignerMiddleware`, or the
464 /// JSON-RPC provider has an unlocked key that can sign using the `eth_sign` call. If none of
465 /// the above conditions are met, then the middleware stack is not capable of signing data.
466 async fn is_signer(&self) -> bool {
467 self.inner().is_signer().await
468 }
469
470 /// Signs data using a specific account. This account needs to be unlocked,
471 /// or the middleware stack must contain a `SignerMiddleware`
472 async fn sign<T: Into<Bytes> + Send + Sync>(
473 &self,
474 data: T,
475 from: &Address,
476 ) -> Result<Signature, Self::Error> {
477 self.inner().sign(data, from).await.map_err(MiddlewareError::from_err)
478 }
479
480 /// Sign a transaction via RPC call
481 async fn sign_transaction(
482 &self,
483 tx: &TypedTransaction,
484 from: Address,
485 ) -> Result<Signature, Self::Error> {
486 self.inner().sign_transaction(tx, from).await.map_err(MiddlewareError::from_err)
487 }
488
489 ////// Contract state
490
491 /// Returns an array (possibly empty) of logs that match the filter
492 async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>, Self::Error> {
493 self.inner().get_logs(filter).await.map_err(MiddlewareError::from_err)
494 }
495
496 /// Returns a stream of logs are loaded in pages of given page size
497 fn get_logs_paginated<'a>(
498 &'a self,
499 filter: &Filter,
500 page_size: u64,
501 ) -> LogQuery<'a, Self::Provider> {
502 self.inner().get_logs_paginated(filter, page_size)
503 }
504
505 /// Install a new filter on the node.
506 ///
507 /// This method is hidden because filter lifecycle should be managed by
508 /// the [`FilterWatcher`]
509 #[doc(hidden)]
510 async fn new_filter(&self, filter: FilterKind<'_>) -> Result<U256, Self::Error> {
511 self.inner().new_filter(filter).await.map_err(MiddlewareError::from_err)
512 }
513
514 /// Uninstalls a filter.
515 ///
516 /// This method is hidden because filter lifecycle should be managed by
517 /// the [`FilterWatcher`]
518 #[doc(hidden)]
519 async fn uninstall_filter<T: Into<U256> + Send + Sync>(
520 &self,
521 id: T,
522 ) -> Result<bool, Self::Error> {
523 self.inner().uninstall_filter(id).await.map_err(MiddlewareError::from_err)
524 }
525
526 /// Streams event logs matching the filter.
527 ///
528 /// This function streams via a polling system, by repeatedly dispatching
529 /// RPC requests. If possible, prefer using a WS or IPC connection and the
530 /// `stream` interface
531 async fn watch<'a>(
532 &'a self,
533 filter: &Filter,
534 ) -> Result<FilterWatcher<'a, Self::Provider, Log>, Self::Error> {
535 self.inner().watch(filter).await.map_err(MiddlewareError::from_err)
536 }
537
538 /// Streams pending transactions.
539 ///
540 /// This function streams via a polling system, by repeatedly dispatching
541 /// RPC requests. If possible, prefer using a WS or IPC connection and the
542 /// `stream` interface
543 async fn watch_pending_transactions(
544 &self,
545 ) -> Result<FilterWatcher<'_, Self::Provider, H256>, Self::Error> {
546 self.inner().watch_pending_transactions().await.map_err(MiddlewareError::from_err)
547 }
548
549 /// Polling method for a filter, which returns an array of logs which occurred since last poll.
550 ///
551 /// This method must be called with one of the following return types, depending on the filter
552 /// type:
553 /// - `eth_newBlockFilter`: [`H256`], returns block hashes
554 /// - `eth_newPendingTransactionFilter`: [`H256`], returns transaction hashes
555 /// - `eth_newFilter`: [`Log`], returns raw logs
556 ///
557 /// If one of these types is not used, decoding will fail and the method will
558 /// return an error.
559 ///
560 /// [`H256`]: ethers_core::types::H256
561 /// [`Log`]: ethers_core::types::Log
562 ///
563 /// This method is hidden because filter lifecycle should be managed by
564 /// the [`FilterWatcher`]
565 #[doc(hidden)]
566 async fn get_filter_changes<T, R>(&self, id: T) -> Result<Vec<R>, Self::Error>
567 where
568 T: Into<U256> + Send + Sync,
569 R: Serialize + DeserializeOwned + Send + Sync + Debug,
570 {
571 self.inner().get_filter_changes(id).await.map_err(MiddlewareError::from_err)
572 }
573
574 /// Streams new block hashes
575 ///
576 /// This function streams via a polling system, by repeatedly dispatching
577 /// RPC requests. If possible, prefer using a WS or IPC connection and the
578 /// `stream` interface
579 async fn watch_blocks(&self) -> Result<FilterWatcher<'_, Self::Provider, H256>, Self::Error> {
580 self.inner().watch_blocks().await.map_err(MiddlewareError::from_err)
581 }
582
583 /// Returns the deployed code at a given address
584 async fn get_code<T: Into<NameOrAddress> + Send + Sync>(
585 &self,
586 at: T,
587 block: Option<BlockId>,
588 ) -> Result<Bytes, Self::Error> {
589 self.inner().get_code(at, block).await.map_err(MiddlewareError::from_err)
590 }
591
592 /// Get the storage of an address for a particular slot location
593 async fn get_storage_at<T: Into<NameOrAddress> + Send + Sync>(
594 &self,
595 from: T,
596 location: H256,
597 block: Option<BlockId>,
598 ) -> Result<H256, Self::Error> {
599 self.inner().get_storage_at(from, location, block).await.map_err(MiddlewareError::from_err)
600 }
601
602 /// Returns the EIP-1186 proof response
603 /// <https://github.com/ethereum/EIPs/issues/1186>
604 async fn get_proof<T: Into<NameOrAddress> + Send + Sync>(
605 &self,
606 from: T,
607 locations: Vec<H256>,
608 block: Option<BlockId>,
609 ) -> Result<EIP1186ProofResponse, Self::Error> {
610 self.inner().get_proof(from, locations, block).await.map_err(MiddlewareError::from_err)
611 }
612
613 /// Returns an indication if this node is currently mining.
614 async fn mining(&self) -> Result<bool, Self::Error> {
615 self.inner().mining().await.map_err(MiddlewareError::from_err)
616 }
617
618 // Personal namespace
619 // NOTE: This will eventually need to be enabled by users explicitly because the personal
620 // namespace is being deprecated:
621 // Issue: https://github.com/ethereum/go-ethereum/issues/25948
622 // PR: https://github.com/ethereum/go-ethereum/pull/26390
623
624 /// Sends the given key to the node to be encrypted with the provided
625 /// passphrase and stored.
626 ///
627 /// The key represents a secp256k1 private key and should be 32 bytes.
628 async fn import_raw_key(
629 &self,
630 private_key: Bytes,
631 passphrase: String,
632 ) -> Result<Address, Self::Error> {
633 self.inner()
634 .import_raw_key(private_key, passphrase)
635 .await
636 .map_err(MiddlewareError::from_err)
637 }
638
639 /// Prompts the node to decrypt the given account from its keystore.
640 ///
641 /// If the duration provided is `None`, then the account will be unlocked
642 /// indefinitely. Otherwise, the account will be unlocked for the provided
643 /// number of seconds.
644 async fn unlock_account<T: Into<Address> + Send + Sync>(
645 &self,
646 account: T,
647 passphrase: String,
648 duration: Option<u64>,
649 ) -> Result<bool, Self::Error> {
650 self.inner()
651 .unlock_account(account, passphrase, duration)
652 .await
653 .map_err(MiddlewareError::from_err)
654 }
655
656 // Admin namespace
657
658 /// Requests adding the given peer, returning a boolean representing
659 /// whether or not the peer was accepted for tracking.
660 async fn add_peer(&self, enode_url: String) -> Result<bool, Self::Error> {
661 self.inner().add_peer(enode_url).await.map_err(MiddlewareError::from_err)
662 }
663
664 /// Requests adding the given peer as a trusted peer, which the node will
665 /// always connect to even when its peer slots are full.
666 async fn add_trusted_peer(&self, enode_url: String) -> Result<bool, Self::Error> {
667 self.inner().add_trusted_peer(enode_url).await.map_err(MiddlewareError::from_err)
668 }
669
670 /// Returns general information about the node as well as information about the running p2p
671 /// protocols (e.g. `eth`, `snap`).
672 async fn node_info(&self) -> Result<NodeInfo, Self::Error> {
673 self.inner().node_info().await.map_err(MiddlewareError::from_err)
674 }
675
676 /// Returns the list of peers currently connected to the node.
677 async fn peers(&self) -> Result<Vec<PeerInfo>, Self::Error> {
678 self.inner().peers().await.map_err(MiddlewareError::from_err)
679 }
680
681 /// Requests to remove the given peer, returning true if the enode was successfully parsed and
682 /// the peer was removed.
683 async fn remove_peer(&self, enode_url: String) -> Result<bool, Self::Error> {
684 self.inner().remove_peer(enode_url).await.map_err(MiddlewareError::from_err)
685 }
686
687 /// Requests to remove the given peer, returning a boolean representing whether or not the
688 /// enode url passed was validated. A return value of `true` does not necessarily mean that the
689 /// peer was disconnected.
690 async fn remove_trusted_peer(&self, enode_url: String) -> Result<bool, Self::Error> {
691 self.inner().remove_trusted_peer(enode_url).await.map_err(MiddlewareError::from_err)
692 }
693
694 // Miner namespace
695
696 /// Starts the miner.
697 async fn start_mining(&self) -> Result<(), Self::Error> {
698 self.inner().start_mining().await.map_err(MiddlewareError::from_err)
699 }
700
701 /// Stop terminates the miner, both at the consensus engine level as well as at
702 /// the block creation level.
703 async fn stop_mining(&self) -> Result<(), Self::Error> {
704 self.inner().stop_mining().await.map_err(MiddlewareError::from_err)
705 }
706
707 // Mempool inspection for Geth's API
708
709 /// Returns the details of all transactions currently pending for inclusion in the next
710 /// block(s), as well as the ones that are being scheduled for future execution only.
711 /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content)
712 async fn txpool_content(&self) -> Result<TxpoolContent, Self::Error> {
713 self.inner().txpool_content().await.map_err(MiddlewareError::from_err)
714 }
715
716 /// Returns a summary of all the transactions currently pending for inclusion in the next
717 /// block(s), as well as the ones that are being scheduled for future execution only.
718 /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect)
719 async fn txpool_inspect(&self) -> Result<TxpoolInspect, Self::Error> {
720 self.inner().txpool_inspect().await.map_err(MiddlewareError::from_err)
721 }
722
723 /// Returns the number of transactions currently pending for inclusion in the next block(s), as
724 /// well as the ones that are being scheduled for future execution only.
725 /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status)
726 async fn txpool_status(&self) -> Result<TxpoolStatus, Self::Error> {
727 self.inner().txpool_status().await.map_err(MiddlewareError::from_err)
728 }
729
730 // Geth `trace` support
731
732 /// After replaying any previous transactions in the same block,
733 /// Replays a transaction, returning the traces configured with passed options
734 async fn debug_trace_transaction(
735 &self,
736 tx_hash: TxHash,
737 trace_options: GethDebugTracingOptions,
738 ) -> Result<GethTrace, Self::Error> {
739 self.inner()
740 .debug_trace_transaction(tx_hash, trace_options)
741 .await
742 .map_err(MiddlewareError::from_err)
743 }
744
745 /// Executes the given call and returns a number of possible traces for it
746 async fn debug_trace_call<T: Into<TypedTransaction> + Send + Sync>(
747 &self,
748 req: T,
749 block: Option<BlockId>,
750 trace_options: GethDebugTracingCallOptions,
751 ) -> Result<GethTrace, Self::Error> {
752 self.inner()
753 .debug_trace_call(req, block, trace_options)
754 .await
755 .map_err(MiddlewareError::from_err)
756 }
757
758 /// Replays all transactions in a given block (specified by block number) and returns the traces
759 /// configured with passed options
760 /// Ref:
761 /// [Here](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtraceblockbynumber)
762 async fn debug_trace_block_by_number(
763 &self,
764 block: Option<BlockNumber>,
765 trace_options: GethDebugTracingOptions,
766 ) -> Result<Vec<GethTrace>, Self::Error> {
767 self.inner()
768 .debug_trace_block_by_number(block, trace_options)
769 .await
770 .map_err(MiddlewareError::from_err)
771 }
772
773 /// Replays all transactions in a given block (specified by block hash) and returns the traces
774 /// configured with passed options
775 /// Ref:
776 /// [Here](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtraceblockbyhash)
777 async fn debug_trace_block_by_hash(
778 &self,
779 block: H256,
780 trace_options: GethDebugTracingOptions,
781 ) -> Result<Vec<GethTrace>, Self::Error> {
782 self.inner()
783 .debug_trace_block_by_hash(block, trace_options)
784 .await
785 .map_err(MiddlewareError::from_err)
786 }
787
788 // Parity `trace` support
789
790 /// Executes the given call and returns a number of possible traces for it
791 async fn trace_call<T: Into<TypedTransaction> + Send + Sync>(
792 &self,
793 req: T,
794 trace_type: Vec<TraceType>,
795 block: Option<BlockNumber>,
796 ) -> Result<BlockTrace, Self::Error> {
797 self.inner().trace_call(req, trace_type, block).await.map_err(MiddlewareError::from_err)
798 }
799
800 /// Executes given calls and returns a number of possible traces for each
801 /// call
802 async fn trace_call_many<T: Into<TypedTransaction> + Send + Sync>(
803 &self,
804 req: Vec<(T, Vec<TraceType>)>,
805 block: Option<BlockNumber>,
806 ) -> Result<Vec<BlockTrace>, Self::Error> {
807 self.inner().trace_call_many(req, block).await.map_err(MiddlewareError::from_err)
808 }
809
810 /// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces
811 async fn trace_raw_transaction(
812 &self,
813 data: Bytes,
814 trace_type: Vec<TraceType>,
815 ) -> Result<BlockTrace, Self::Error> {
816 self.inner()
817 .trace_raw_transaction(data, trace_type)
818 .await
819 .map_err(MiddlewareError::from_err)
820 }
821
822 /// Replays a transaction, returning the traces
823 async fn trace_replay_transaction(
824 &self,
825 hash: H256,
826 trace_type: Vec<TraceType>,
827 ) -> Result<BlockTrace, Self::Error> {
828 self.inner()
829 .trace_replay_transaction(hash, trace_type)
830 .await
831 .map_err(MiddlewareError::from_err)
832 }
833
834 /// Replays all transactions in a block returning the requested traces for each transaction
835 async fn trace_replay_block_transactions(
836 &self,
837 block: BlockNumber,
838 trace_type: Vec<TraceType>,
839 ) -> Result<Vec<BlockTrace>, Self::Error> {
840 self.inner()
841 .trace_replay_block_transactions(block, trace_type)
842 .await
843 .map_err(MiddlewareError::from_err)
844 }
845
846 /// Returns traces created at given block
847 async fn trace_block(&self, block: BlockNumber) -> Result<Vec<Trace>, Self::Error> {
848 self.inner().trace_block(block).await.map_err(MiddlewareError::from_err)
849 }
850
851 /// Return traces matching the given filter
852 async fn trace_filter(&self, filter: TraceFilter) -> Result<Vec<Trace>, Self::Error> {
853 self.inner().trace_filter(filter).await.map_err(MiddlewareError::from_err)
854 }
855
856 /// Returns trace at the given position
857 async fn trace_get<T: Into<U64> + Send + Sync>(
858 &self,
859 hash: H256,
860 index: Vec<T>,
861 ) -> Result<Trace, Self::Error> {
862 self.inner().trace_get(hash, index).await.map_err(MiddlewareError::from_err)
863 }
864
865 /// Returns all traces of a given transaction
866 async fn trace_transaction(&self, hash: H256) -> Result<Vec<Trace>, Self::Error> {
867 self.inner().trace_transaction(hash).await.map_err(MiddlewareError::from_err)
868 }
869
870 // Parity namespace
871
872 /// Returns all receipts for that block. Must be done on a parity node.
873 async fn parity_block_receipts<T: Into<BlockNumber> + Send + Sync>(
874 &self,
875 block: T,
876 ) -> Result<Vec<TransactionReceipt>, Self::Error> {
877 self.inner().parity_block_receipts(block).await.map_err(MiddlewareError::from_err)
878 }
879
880 /// Create a new subscription
881 ///
882 /// This method is hidden as subscription lifecycles are intended to be
883 /// handled by a [`SubscriptionStream`] object.
884 #[doc(hidden)]
885 async fn subscribe<T, R>(
886 &self,
887 params: T,
888 ) -> Result<SubscriptionStream<'_, Self::Provider, R>, Self::Error>
889 where
890 T: Debug + Serialize + Send + Sync,
891 R: DeserializeOwned + Send + Sync,
892 <Self as Middleware>::Provider: PubsubClient,
893 {
894 self.inner().subscribe(params).await.map_err(MiddlewareError::from_err)
895 }
896
897 /// Instruct the RPC to cancel a subscription by its ID
898 ///
899 /// This method is hidden as subscription lifecycles are intended to be
900 /// handled by a [`SubscriptionStream`] object
901 #[doc(hidden)]
902 async fn unsubscribe<T>(&self, id: T) -> Result<bool, Self::Error>
903 where
904 T: Into<U256> + Send + Sync,
905 <Self as Middleware>::Provider: PubsubClient,
906 {
907 self.inner().unsubscribe(id).await.map_err(MiddlewareError::from_err)
908 }
909
910 /// Subscribe to a stream of incoming blocks.
911 ///
912 /// This function is only available on pubsub clients, such as Websockets
913 /// or IPC. For a polling alternative available over HTTP, use
914 /// [`Middleware::watch_blocks`]. However, be aware that polling increases
915 /// RPC usage drastically.
916 async fn subscribe_blocks(
917 &self,
918 ) -> Result<SubscriptionStream<'_, Self::Provider, Block<TxHash>>, Self::Error>
919 where
920 <Self as Middleware>::Provider: PubsubClient,
921 {
922 self.inner().subscribe_blocks().await.map_err(MiddlewareError::from_err)
923 }
924
925 /// Subscribe to a stream of pending transaction hashes.
926 ///
927 /// This function is only available on pubsub clients, such as Websockets
928 /// or IPC. For a polling alternative available over HTTP, use
929 /// [`Middleware::watch_pending_transactions`]. However, be aware that
930 /// polling increases RPC usage drastically.
931 async fn subscribe_pending_txs(
932 &self,
933 ) -> Result<SubscriptionStream<'_, Self::Provider, TxHash>, Self::Error>
934 where
935 <Self as Middleware>::Provider: PubsubClient,
936 {
937 self.inner().subscribe_pending_txs().await.map_err(MiddlewareError::from_err)
938 }
939
940 /// Subscribe to a stream of pending transaction bodies.
941 ///
942 /// This function is only available on pubsub clients, such as Websockets
943 /// or IPC. For a polling alternative available over HTTP, use
944 /// [`Middleware::watch_pending_transactions`]. However, be aware that
945 /// polling increases RPC usage drastically.
946 ///
947 /// Note: This endpoint is compatible only with Geth client version 1.11.0 or later.
948 async fn subscribe_full_pending_txs(
949 &self,
950 ) -> Result<SubscriptionStream<'_, Self::Provider, Transaction>, Self::Error>
951 where
952 <Self as Middleware>::Provider: PubsubClient,
953 {
954 self.inner().subscribe_full_pending_txs().await.map_err(MiddlewareError::from_err)
955 }
956
957 /// Subscribe to a stream of event logs matchin the provided [`Filter`].
958 ///
959 /// This function is only available on pubsub clients, such as Websockets
960 /// or IPC. For a polling alternative available over HTTP, use
961 /// [`Middleware::watch`]. However, be aware that polling increases
962 /// RPC usage drastically.
963 async fn subscribe_logs<'a>(
964 &'a self,
965 filter: &Filter,
966 ) -> Result<SubscriptionStream<'a, Self::Provider, Log>, Self::Error>
967 where
968 <Self as Middleware>::Provider: PubsubClient,
969 {
970 self.inner().subscribe_logs(filter).await.map_err(MiddlewareError::from_err)
971 }
972
973 /// Query the node for a [`FeeHistory`] object. This objct contains
974 /// information about the EIP-1559 base fee in past blocks, as well as gas
975 /// utilization within those blocks.
976 ///
977 /// See the
978 /// [EIP-1559 documentation](https://eips.ethereum.org/EIPS/eip-1559) for
979 /// details
980 async fn fee_history<T: Into<U256> + serde::Serialize + Send + Sync>(
981 &self,
982 block_count: T,
983 last_block: BlockNumber,
984 reward_percentiles: &[f64],
985 ) -> Result<FeeHistory, Self::Error> {
986 self.inner()
987 .fee_history(block_count, last_block, reward_percentiles)
988 .await
989 .map_err(MiddlewareError::from_err)
990 }
991
992 /// Query the node for an EIP-2930 Access List.
993 ///
994 /// See the
995 /// [EIP-2930 documentation](https://eips.ethereum.org/EIPS/eip-2930) for
996 /// details
997 async fn create_access_list(
998 &self,
999 tx: &TypedTransaction,
1000 block: Option<BlockId>,
1001 ) -> Result<AccessListWithGasUsed, Self::Error> {
1002 self.inner().create_access_list(tx, block).await.map_err(MiddlewareError::from_err)
1003 }
1004}
1005
1006#[cfg(feature = "celo")]
1007#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
1008#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
1009/// Celo-specific extension trait
1010pub trait CeloMiddleware: Middleware {
1011 /// Get validator BLS public keys
1012 async fn get_validators_bls_public_keys<T: Into<BlockId> + Send + Sync>(
1013 &self,
1014 block_id: T,
1015 ) -> Result<Vec<String>, ProviderError> {
1016 self.provider()
1017 .get_validators_bls_public_keys(block_id)
1018 .await
1019 .map_err(MiddlewareError::from_err)
1020 }
1021}
1022
1023#[cfg(feature = "celo")]
1024#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
1025#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
1026impl<T> CeloMiddleware for T where T: Middleware {}