Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit e2e2982

Browse files
authored
Merge pull request #885 from celo-org/carterqw2/call-tracer
Implement fetching internal transactions from callTracer
2 parents b352db7 + b4d0f51 commit e2e2982

File tree

9 files changed

+458
-8
lines changed

9 files changed

+458
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Features
44

5+
- [#6721](https://github.com/blockscout/blockscout/pull/6721) - Implement fetching internal transactions from callTracer
56
- [#5561](https://github.com/blockscout/blockscout/pull/5561), [#6523](https://github.com/blockscout/blockscout/pull/6523) - Improve working with contracts implementations
67
- [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization
78
- [#6481](https://github.com/blockscout/blockscout/pull/6481) - Smart contract verification improvements
@@ -29,6 +30,7 @@
2930

3031
### Fixes
3132

33+
- [#6827](https://github.com/blockscout/blockscout/pull/6827) - Fix handling unknown calls from `callTracer`
3234
- [#6532](https://github.com/blockscout/blockscout/pull/6532) - Fix index creation migration
3335
- [#6473](https://github.com/blockscout/blockscout/pull/6473) - Fix state changes for contract creation transactions
3436
- [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening

apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex

+75-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ defmodule EthereumJSONRPC.Geth do
33
Ethereum JSONRPC methods that are only supported by [Geth](https://github.com/ethereum/go-ethereum/wiki/geth).
44
"""
55

6+
require Logger
7+
68
import EthereumJSONRPC, only: [id_to_params: 1, integer_to_quantity: 1, json_rpc: 2, request: 1]
79

810
alias EthereumJSONRPC.{FetchedBalance, FetchedCode, PendingTransaction}
@@ -78,12 +80,18 @@ defmodule EthereumJSONRPC.Geth do
7880
defp debug_trace_transaction_request(%{id: id, hash_data: hash_data}) do
7981
timeout = Application.get_env(:ethereum_jsonrpc, :internal_transaction_timeout)
8082

83+
tracer =
84+
case Application.get_env(:ethereum_jsonrpc, __MODULE__)[:tracer] do
85+
"js" -> @tracer
86+
"call_tracer" -> "callTracer"
87+
end
88+
8189
request(%{
8290
id: id,
8391
method: "debug_traceTransaction",
8492
params: [
8593
hash_data,
86-
%{tracer: @tracer, disableStack: true, disableMemory: true, disableStorage: true, timeout: timeout}
94+
%{tracer: tracer, disableStack: true, disableMemory: true, disableStorage: true, timeout: timeout}
8795
]
8896
})
8997
end
@@ -177,6 +185,7 @@ defmodule EthereumJSONRPC.Geth do
177185

178186
internal_transaction_params =
179187
calls
188+
|> prepare_calls()
180189
|> Stream.with_index()
181190
|> Enum.map(fn {trace, index} ->
182191
Map.merge(trace, %{
@@ -223,6 +232,71 @@ defmodule EthereumJSONRPC.Geth do
223232
{:error, annotated_error}
224233
end
225234

235+
defp prepare_calls(calls) do
236+
case Application.get_env(:ethereum_jsonrpc, __MODULE__)[:tracer] do
237+
"call_tracer" -> {calls, 0} |> parse_call_tracer_calls([], [], false) |> Enum.reverse()
238+
"js" -> calls
239+
end
240+
end
241+
242+
defp parse_call_tracer_calls(calls, acc, trace_address, inner? \\ true)
243+
defp parse_call_tracer_calls([], acc, _trace_address, _inner?), do: acc
244+
defp parse_call_tracer_calls({%{"type" => 0}, _}, acc, _trace_address, _inner?), do: acc
245+
246+
defp parse_call_tracer_calls(
247+
{%{"type" => type, "from" => from} = call, index},
248+
acc,
249+
trace_address,
250+
inner?
251+
)
252+
when type in ~w(CALL CALLCODE DELEGATECALL STATICCALL CREATE CREATE2 SELFDESTRUCT REWARD) do
253+
new_trace_address = [index | trace_address]
254+
255+
formatted_call =
256+
%{
257+
"type" => if(type in ~w(CALL CALLCODE DELEGATECALL STATICCALL), do: "call", else: String.downcase(type)),
258+
"callType" => String.downcase(type),
259+
"from" => from,
260+
"to" => Map.get(call, "to", "0x"),
261+
"createdContractAddressHash" => Map.get(call, "to", "0x"),
262+
"value" => Map.get(call, "value", "0x0"),
263+
"gas" => Map.get(call, "gas", "0x0"),
264+
"gasUsed" => Map.get(call, "gasUsed", "0x0"),
265+
"input" => Map.get(call, "input", "0x"),
266+
"init" => Map.get(call, "input", "0x"),
267+
"createdContractCode" => Map.get(call, "output", "0x"),
268+
"traceAddress" => if(inner?, do: Enum.reverse(new_trace_address), else: []),
269+
"error" => call["error"]
270+
}
271+
|> case do
272+
%{"error" => nil} = ok_call ->
273+
ok_call
274+
|> Map.delete("error")
275+
# to handle staticcall, all other cases handled by EthereumJSONRPC.Geth.Call.elixir_to_internal_transaction_params/1
276+
|> Map.put("output", Map.get(call, "output", "0x"))
277+
278+
error_call ->
279+
error_call
280+
end
281+
282+
parse_call_tracer_calls(
283+
Map.get(call, "calls", []),
284+
[formatted_call | acc],
285+
if(inner?, do: new_trace_address, else: [])
286+
)
287+
end
288+
289+
defp parse_call_tracer_calls({call, _}, acc, _trace_address, _inner?) do
290+
Logger.warning("Call from a callTracer with an unknown type: #{inspect(call)}")
291+
acc
292+
end
293+
294+
defp parse_call_tracer_calls(calls, acc, trace_address, _inner) when is_list(calls) do
295+
calls
296+
|> Stream.with_index()
297+
|> Enum.reduce(acc, &parse_call_tracer_calls(&1, &2, trace_address))
298+
end
299+
226300
defp reduce_internal_transactions_params(internal_transactions_params) when is_list(internal_transactions_params) do
227301
internal_transactions_params
228302
|> Enum.reduce({:ok, []}, &internal_transactions_params_reducer/2)

0 commit comments

Comments
 (0)