Repository: gakonst/ethers-rs
Pull request #792 (2022-01-14 19:12:07)

Implement trace_callMany
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md

The contributors guide includes instructions for running rustfmt and building the
documentation.
-->

## Motivation

<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

Implement [trace_callMany](https://openethereum.github.io/JSONRPC-trace-module#trace_callmany)

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

Actually do this. I will also need to implement `ErigonInstance` so I can add test for this.
Now it actually works with my local node
```sh
◆ ethers-fork git:(master) ✗ ❯❯❯ cargo test -p ethers-providers --lib -- --nocapture provider::tests::test_trace_call_many
   Compiling ethers-providers v0.6.0 (/Users/eugene/Developer/rust/ethers-fork/ethers-providers)
    Finished test [unoptimized + debuginfo] target(s) in 3.52s
     Running unittests (target/debug/deps/ethers_providers-6eb7cba4c6e73967)

running 1 test
[ethers-providers/src/provider.rs:1485] traces = [
    BlockTrace {
        output: Bytes(
            b"",
        ),
        trace: Some(
            [],
        ),
        vm_trace: None,
        state_diff: Some(
            StateDiff(
                {
                    0x0000000000000000000000000000000000000000: AccountDiff {
                        balance: Changed(
                            ChangedType {
                                from: 11326881149672971579810,
                                to: 1553734685634137288388564520290,
                            },
                        ),
                        nonce: Changed(
                            ChangedType {
                                from: 0,
                                to: 1,
                            },
                        ),
                        code: Same,
                        storage: {},
                    },
                    0x0000000000000000000000000000000000000001: AccountDiff {
                        balance: Changed(
                            ChangedType {
                                from: 13629332194864958173,
                                to: 13639332194864958173,
                            },
                        ),
                        nonce: Same,
                        code: Same,
                        storage: {},
                    },
                },
            ),
        ),
        transaction_hash: None,
    },
    BlockTrace {
        output: Bytes(
            b"\xe3\xb0\xc4B\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99o\xb9$'\xaeA\xe4d\x9b\x93L\xa4\x95\x99\x1bxR\xb8U",
        ),
        trace: Some(
            [],
        ),
        vm_trace: None,
        state_diff: Some(
            StateDiff(
                {
                    0x0000000000000000000000000000000000000001: AccountDiff {
                        balance: Changed(
                            ChangedType {
                                from: 13639332194864958173,
                                to: 1553734674320895966171835647553,
                            },
                        ),
                        nonce: Changed(
                            ChangedType {
                                from: 0,
                                to: 1,
                            },
                        ),
                        code: Same,
                        storage: {},
                    },
                    0x0000000000000000000000000000000000000002: AccountDiff {
                        balance: Changed(
                            ChangedType {
                                from: 171628435084204064,
                                to: 181628435084204064,
                            },
                        ),
                        nonce: Same,
                        code: Same,
                        storage: {},
                    },
                },
            ),
        ),
        transaction_hash: None,
    },
]
test provider::tests::test_trace_call_many ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 25 filtered out; finished in 0.14s
```

## PR Checklist

- [ ] Added Tests
- [ ] Added Documentation
- [ ] Updated the changelog



Patch:
diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs
index 66547cec..696fa8c4 100644
--- a/ethers-providers/src/lib.rs
+++ b/ethers-providers/src/lib.rs
@@ -480,6 +480,14 @@ pub trait Middleware: Sync + Send + Debug {
         self.inner().trace_call(req, trace_type, block).await.map_err(FromErr::from)
     }
 
+    async fn trace_call_many<T: Into<TypedTransaction> + Send + Sync>(
+        &self,
+        req: Vec<(T, Vec<TraceType>)>,
+        block: Option<BlockNumber>,
+    ) -> Result<Vec<BlockTrace>, Self::Error> {
+        self.inner().trace_call_many(req, block).await.map_err(FromErr::from)
+    }
+
     /// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces
     async fn trace_raw_transaction(
         &self,
diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs
index 8d2617cb..516986e8 100644
--- a/ethers-providers/src/provider.rs
+++ b/ethers-providers/src/provider.rs
@@ -797,6 +797,19 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
         self.request("trace_call", [req, trace_type, block]).await
     }
 
+    /// Executes given calls and returns a number of possible traces for each call
+    async fn trace_call_many<T: Into<TypedTransaction> + Send + Sync>(
+        &self,
+        req: Vec<(T, Vec<TraceType>)>,
+        block: Option<BlockNumber>,
+    ) -> Result<Vec<BlockTrace>, ProviderError> {
+        let req: Vec<(TypedTransaction, Vec<TraceType>)> =
+            req.into_iter().map(|(tx, trace_type)| (tx.into(), trace_type)).collect();
+        let req = utils::serialize(&req);
+        let block = utils::serialize(&block.unwrap_or(BlockNumber::Latest));
+        self.request("trace_callMany", [req, block]).await
+    }
+
     /// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces
     async fn trace_raw_transaction(
         &self,
@@ -1434,4 +1447,42 @@ mod tests {
             provider.fee_history(10u64, BlockNumber::Latest, &[10.0, 40.0]).await.unwrap();
         dbg!(&history);
     }
+
+    #[tokio::test]
+    #[ignore]
+    async fn test_trace_call_many() {
+        // TODO: Implement ErigonInstance, so it'd be possible to test this.
+        let provider = Provider::new(Ws::connect("ws://127.0.0.1:8545").await.unwrap());
+        let traces = provider
+            .trace_call_many(
+                vec![
+                    (
+                        TransactionRequest::new()
+                            .from(Address::zero())
+                            .to("0x0000000000000000000000000000000000000001"
+                                .parse::<H160>()
+                                .unwrap())
+                            .value(U256::from(10000000000000000u128)),
+                        vec![TraceType::StateDiff],
+                    ),
+                    (
+                        TransactionRequest::new()
+                            .from(
+                                "0x0000000000000000000000000000000000000001"
+                                    .parse::<H160>()
+                                    .unwrap(),
+                            )
+                            .to("0x0000000000000000000000000000000000000002"
+                                .parse::<H160>()
+                                .unwrap())
+                            .value(U256::from(10000000000000000u128)),
+                        vec![TraceType::StateDiff],
+                    ),
+                ],
+                None,
+            )
+            .await
+            .unwrap();
+        dbg!(traces);
+    }
 }


Test patch:
diff --git a/ethers-contract/tests/contract.rs b/ethers-contract/tests/contract.rs
index 8748af2b..17bfe11e 100644
--- a/ethers-contract/tests/contract.rs
+++ b/ethers-contract/tests/contract.rs
@@ -570,12 +570,12 @@ mod eth_tests {
         };
 
         let derived_foo_bar = deriveeip712test_mod::FooBar {
-            foo: foo_bar.foo.clone(),
-            bar: foo_bar.bar.clone(),
+            foo: foo_bar.foo,
+            bar: foo_bar.bar,
             fizz: foo_bar.fizz.clone(),
-            buzz: foo_bar.buzz.clone(),
+            buzz: foo_bar.buzz,
             far: foo_bar.far.clone(),
-            out: foo_bar.out.clone(),
+            out: foo_bar.out,
         };
 
         let sig = wallet.sign_typed_data(&foo_bar).await.expect("failed to sign typed data");