Explorer.JSONRPC -> EthereumJSONRPC

Extract Explorer.JSONRPC to its own OTP application,
apps/ethereum_jsonrpc.  It is not ready to be a completely separate
library because it knowns the internal params format used for
Explorer.Chain.
pull/162/head
Luke Imhoff 7 years ago
parent 75388c8ece
commit 11bcecad96
  1. 33
      apps/ethereum_jsonrpc/README.md
  2. 30
      apps/ethereum_jsonrpc/config/config.exs
  3. 301
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
  4. 16
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/application.ex
  5. 60
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex
  6. 12
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex
  7. 20
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/log.ex
  8. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/logs.ex
  9. 8
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity.ex
  10. 22
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace.ex
  11. 12
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace/action.ex
  12. 10
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/trace/result.ex
  13. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/parity/traces.ex
  14. 46
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipt.ex
  15. 12
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex
  16. 63
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
  17. 10
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transactions.ex
  18. 44
      apps/ethereum_jsonrpc/mix.exs
  19. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/block_test.exs
  20. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/blocks_test.exs
  21. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/log_test.exs
  22. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity/trace/action_test.exs
  23. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity/trace/result_test.exs
  24. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity/trace_test.exs
  25. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/parity_test.exs
  26. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/receipt_test.exs
  27. 6
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/receipts_test.exs
  28. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs
  29. 5
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transactions_test.exs
  30. 8
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs
  31. 6
      apps/ethereum_jsonrpc/test/test_helper.exs
  32. 5
      apps/explorer/config/config.exs
  33. 1
      apps/explorer/lib/explorer/application.ex
  34. 11
      apps/explorer/lib/explorer/indexer/address_fetcher.ex
  35. 11
      apps/explorer/lib/explorer/indexer/block_fetcher.ex
  36. 309
      apps/explorer/lib/explorer/jsonrpc.ex
  37. 2
      apps/explorer/mix.exs
  38. 2
      apps/explorer/test/explorer/indexer/address_fetcher_test.exs
  39. 3
      apps/explorer/test/explorer/indexer/block_fetcher_test.exs
  40. 5
      apps/explorer/test/explorer/jsonrpc/block_test.exs
  41. 5
      apps/explorer/test/explorer/jsonrpc/blocks_test.exs
  42. 5
      apps/explorer/test/explorer/jsonrpc/log_test.exs
  43. 5
      apps/explorer/test/explorer/jsonrpc/parity/trace/action_test.exs
  44. 5
      apps/explorer/test/explorer/jsonrpc/parity/trace/result_test.exs
  45. 5
      apps/explorer/test/explorer/jsonrpc/parity/trace_test.exs
  46. 5
      apps/explorer/test/explorer/jsonrpc/parity_test.exs
  47. 5
      apps/explorer/test/explorer/jsonrpc/receipt_test.exs
  48. 5
      apps/explorer/test/explorer/jsonrpc/transaction_test.exs
  49. 5
      apps/explorer/test/explorer/jsonrpc/transactions_test.exs
  50. 2
      coveralls.json

@ -1,21 +1,36 @@
# EthereumJsonrpc
# EthereumJSONRPC
**TODO: Add description**
Ethereum JSONRPC client.
## Configuration
Configuration for parity URLs can be provided with the following mix
config:
```elixir
config :ethereum_jsonrpc,
url: "https://sokol.poa.network",
trace_url: "https://sokol-trace.poa.network",
http: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :ethereum_jsonrpc]]
```
Note: the tracing node URL is provided separately from `:url`,
via `:trace_url`. The trace URL and is used for
`fetch_internal_transactions`, which is only a supported method on
tracing nodes. The `:http` option is passed directly to the HTTP
library (`HTTPoison`), which forwards the options down to `:hackney`.
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `ethereum_jsonrpc` to your list of dependencies in `mix.exs`:
The OTP application `:ethereum_jsonrpc` can be used in other umbrella
OTP applications by adding `ethereum_jsonrpc` to your list of
dependencies in `mix.exs`:
```elixir
def deps do
[
{:ethereum_jsonrpc, "~> 0.1.0"}
{:ethereum_jsonrpc, in_umbrella: true}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/ethereum_jsonrpc](https://hexdocs.pm/ethereum_jsonrpc).

@ -2,29 +2,7 @@
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config
# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for
# 3rd-party users, it should be done in your "mix.exs" file.
# You can configure your application as:
#
# config :ethereum_jsonrpc, key: :value
#
# and access this configuration in your application as:
#
# Application.get_env(:ethereum_jsonrpc, :key)
#
# You can also configure a 3rd-party app:
#
# config :logger, level: :info
#
# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env}.exs"
config :ethereum_jsonrpc,
http: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :ethereum_jsonrpc]],
trace_url: "https://sokol-trace.poa.network",
url: "https://sokol.poa.network"

@ -1,18 +1,303 @@
defmodule EthereumJsonrpc do
defmodule EthereumJSONRPC do
@moduledoc """
Documentation for EthereumJsonrpc.
Ethereum JSONRPC client.
## Configuration
Configuration for parity URLs can be provided with the following mix config:
config :ethereum_jsonrpc,
url: "https://sokol.poa.network",
trace_url: "https://sokol-trace.poa.network",
http: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :ethereum_jsonrpc]]
Note: the tracing node URL is provided separately from `:url`, via `:trace_url`. The trace URL and is used for
`fetch_internal_transactions`, which is only a supported method on tracing nodes. The `:http` option is passed
directly to the HTTP library (`HTTPoison`), which forwards the options down to `:hackney`.
"""
require Logger
alias EthereumJSONRPC.{Blocks, Parity, Receipts, Transactions}
@typedoc """
Truncated 20-byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash encoded as a hexadecimal number in a
`String.t`.
"""
@type address :: String.t()
@typedoc """
Binary data encoded as a single hexadecimal number in a `String.t`
"""
@type data :: String.t()
@typedoc """
A full 32-byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash encoded as a hexadecimal number in a `String.t`
## Example
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
"""
@type hash :: String.t()
@typedoc """
8 byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash of the proof-of-work.
"""
@type nonce :: String.t()
@typedoc """
A number encoded as a hexadecimal number in a `String.t`
## Example
"0x1b4"
"""
@type quantity :: String.t()
@typedoc """
Unix timestamp encoded as a hexadecimal number in a `String.t`
"""
@type timestamp :: String.t()
@doc """
Hello world.
Lists changes for a given filter subscription.
"""
def check_for_updates(filter_id) do
request = %{
"id" => filter_id,
"jsonrpc" => "2.0",
"method" => "eth_getFilterChanges",
"params" => [filter_id]
}
## Examples
json_rpc(request, config(:url))
end
iex> EthereumJsonrpc.hello
:world
@doc """
Fetches configuration for this module under `key`
Configuration can be set a compile time using `config`
config :ethereume_jsonrpc, key, value
Configuration can be set a runtime using `Application.put_env/3`
Application.put_env(:ethereume_jsonrpc, key, value)
"""
def config(key) do
Application.fetch_env!(:ethereum_jsonrpc, key)
end
@doc """
Fetches address balances by address hashes.
"""
def fetch_balances_by_hash(address_hashes) do
batched_requests =
for hash <- address_hashes do
%{
"id" => hash,
"jsonrpc" => "2.0",
"method" => "eth_getBalance",
"params" => [hash, "latest"]
}
end
batched_requests
|> json_rpc(config(:url))
|> handle_balances()
end
defp handle_balances({:ok, results}) do
native_results =
for response <- results, into: %{} do
{response["id"], hexadecimal_to_integer(response["result"])}
end
{:ok, native_results}
end
defp handle_balances({:error, _reason} = err), do: err
@doc """
Fetches blocks by block hashes.
Transaction data is included for each block.
"""
def hello do
:world
def fetch_blocks_by_hash(block_hashes) do
batched_requests =
for block_hash <- block_hashes do
%{
"id" => block_hash,
"jsonrpc" => "2.0",
"method" => "eth_getBlockByHash",
"params" => [block_hash, true]
}
end
batched_requests
|> json_rpc(config(:url))
|> handle_get_block_by_number()
|> case do
{:ok, _next, results} -> {:ok, results}
{:error, reason} -> {:error, reason}
end
end
@doc """
Fetches blocks by block number range.
"""
def fetch_blocks_by_range(block_start, block_end) do
block_start
|> build_batch_get_block_by_number(block_end)
|> json_rpc(config(:url))
|> handle_get_block_by_number()
end
@doc """
Fetches internal transactions from client-specific API.
"""
def fetch_internal_transactions(hashes) when is_list(hashes) do
Parity.fetch_internal_transactions(hashes)
end
def fetch_transaction_receipts(hashes) when is_list(hashes) do
Receipts.fetch(hashes)
end
@doc """
1. POSTs JSON `payload` to `url`
2. Decodes the response
3. Handles the response
## Returns
* Handled response
* `{:error, reason}` if POST failes
"""
def json_rpc(payload, url) do
json = encode_json(payload)
headers = [{"Content-Type", "application/json"}]
case HTTPoison.post(url, json, headers, config(:http)) do
{:ok, %HTTPoison.Response{body: body, status_code: code}} ->
body |> decode_json(payload, url) |> handle_response(code)
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
@doc """
Creates a filter subscription that can be polled for retreiving new blocks.
"""
def listen_for_new_blocks do
id = DateTime.utc_now() |> DateTime.to_unix()
request = %{
"id" => id,
"jsonrpc" => "2.0",
"method" => "eth_newBlockFilter",
"params" => []
}
json_rpc(request, config(:url))
end
@doc """
Converts `t:nonce/0` to `t:non_neg_integer/0`
"""
def nonce_to_integer(nonce) do
hexadecimal_to_integer(nonce)
end
@doc """
Converts `t:quantity/0` to `t:non_neg_integer/0`.
"""
def quantity_to_integer(quantity) do
hexadecimal_to_integer(quantity)
end
@doc """
Converts `t:timestamp/0` to `t:DateTime.t/0`
"""
def timestamp_to_datetime(timestamp) do
timestamp
|> hexadecimal_to_integer()
|> Timex.from_unix()
end
defp build_batch_get_block_by_number(block_start, block_end) do
for current <- block_start..block_end do
%{
"id" => current,
"jsonrpc" => "2.0",
"method" => "eth_getBlockByNumber",
"params" => [int_to_hash_string(current), true]
}
end
end
defp encode_json(data), do: Jason.encode_to_iodata!(data)
defp decode_json(body, posted_payload, url) do
Jason.decode!(body)
rescue
Jason.DecodeError ->
Logger.error("""
failed to decode json payload:
url: #{inspect(url)}
body: #{inspect(body)}
posted payload: #{inspect(posted_payload)}
""")
raise("bad jason")
end
defp handle_get_block_by_number({:ok, results}) do
{blocks, next} =
Enum.reduce(results, {[], :more}, fn
%{"result" => nil}, {blocks, _} -> {blocks, :end_of_chain}
%{"result" => %{} = block}, {blocks, next} -> {[block | blocks], next}
end)
elixir_blocks = Blocks.to_elixir(blocks)
elixir_transactions = Blocks.elixir_to_transactions(elixir_blocks)
blocks_params = Blocks.elixir_to_params(elixir_blocks)
transactions_params = Transactions.elixir_to_params(elixir_transactions)
{:ok, next,
%{
blocks: blocks_params,
transactions: transactions_params
}}
end
defp handle_get_block_by_number({:error, reason}) do
{:error, reason}
end
defp handle_response(resp, 200) do
case resp do
[%{} | _] = batch_resp -> {:ok, batch_resp}
%{"error" => error} -> {:error, error}
%{"result" => result} -> {:ok, result}
end
end
defp handle_response(resp, _status) do
{:error, resp}
end
defp hexadecimal_to_integer("0x" <> hexadecimal_digits) do
String.to_integer(hexadecimal_digits, 16)
end
defp int_to_hash_string(number), do: "0x" <> Integer.to_string(number, 16)
end

@ -0,0 +1,16 @@
defmodule EthereumJSONRPC.Application do
@moduledoc """
Starts `:hackney_pool` `:ethereum_jsonrpc`.
"""
use Application
@impl Application
def start(_type, _args) do
children = [
:hackney_pool.child_spec(:ethereum_jsonrpc, recv_timeout: 60_000, timeout: 60_000, max_connections: 1000)
]
Supervisor.start_link(children, strategy: :one_for_one, name: EthereumJSONRPC.Supervisor)
end
end

@ -1,55 +1,55 @@
defmodule Explorer.JSONRPC.Block do
defmodule EthereumJSONRPC.Block do
@moduledoc """
Block format as returned by [`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash)
and [`eth_getBlockByNumber`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber).
"""
import Explorer.JSONRPC, only: [nonce_to_integer: 1, quantity_to_integer: 1, timestamp_to_datetime: 1]
import EthereumJSONRPC, only: [nonce_to_integer: 1, quantity_to_integer: 1, timestamp_to_datetime: 1]
alias Explorer.JSONRPC
alias Explorer.JSONRPC.Transactions
alias EthereumJSONRPC
alias EthereumJSONRPC.Transactions
@type elixir :: %{String.t() => non_neg_integer | DateTime.t() | String.t() | nil}
@typedoc """
* `"author"` - `t:Explorer.JSONRPC.address/0` that created the block. Aliased by `"miner"`.
* `"difficulty"` - `t:Explorer.JSONRPC.quantity/0`` of the difficulty for this block.
* `"extraData"` - the extra `t:Explorer.JSONRPC.data/0`` field of this block.
* `"gasLimit" - maximum gas `t:Explorer.JSONRPC.quantity/0`` in this block.
* `"gasUsed" - the total `t:Explorer.JSONRPC.quantity/0`` of gas used by all transactions in this block.
* `"hash"` - the `t:Explorer.JSONRPC.hash/0` of the block.
* `"logsBloom"` - `t:Explorer.JSONRPC.data/0`` for the [Bloom filter](https://en.wikipedia.org/wiki/Bloom_filter)
* `"author"` - `t:EthereumJSONRPC.address/0` that created the block. Aliased by `"miner"`.
* `"difficulty"` - `t:EthereumJSONRPC.quantity/0`` of the difficulty for this block.
* `"extraData"` - the extra `t:EthereumJSONRPC.data/0`` field of this block.
* `"gasLimit" - maximum gas `t:EthereumJSONRPC.quantity/0`` in this block.
* `"gasUsed" - the total `t:EthereumJSONRPC.quantity/0`` of gas used by all transactions in this block.
* `"hash"` - the `t:EthereumJSONRPC.hash/0` of the block.
* `"logsBloom"` - `t:EthereumJSONRPC.data/0`` for the [Bloom filter](https://en.wikipedia.org/wiki/Bloom_filter)
for the logs of the block. `nil` when block is pending.
* `"miner"` - `t:Explorer.JSONRPC.address/0` of the beneficiary to whom the mining rewards were given. Aliased by
* `"miner"` - `t:EthereumJSONRPC.address/0` of the beneficiary to whom the mining rewards were given. Aliased by
`"author"`.
* `"nonce"` - `t:Explorer.JSONRPC.nonce/0`. `nil` when its pending block.
* `"number"` - the block number `t:Explorer.JSONRPC.quantity/0`. `nil` when block is pending.
* `"parentHash" - the `t:Explorer.JSONRPC.hash/0` of the parent block.
* `"receiptsRoot"` - `t:Explorer.JSONRPC.hash/0` of the root of the receipts.
* `"nonce"` - `t:EthereumJSONRPC.nonce/0`. `nil` when its pending block.
* `"number"` - the block number `t:EthereumJSONRPC.quantity/0`. `nil` when block is pending.
* `"parentHash" - the `t:EthereumJSONRPC.hash/0` of the parent block.
* `"receiptsRoot"` - `t:EthereumJSONRPC.hash/0` of the root of the receipts.
[trie](https://github.com/ethereum/wiki/wiki/Patricia-Tree) of the block.
* `"sealFields"` - UNKNOWN
* `"sha3Uncles"` - `t:Explorer.JSONRPC.hash/0` of the
* `"sha3Uncles"` - `t:EthereumJSONRPC.hash/0` of the
[uncles](https://bitcoin.stackexchange.com/questions/39329/in-ethereum-what-is-an-uncle-block) data in the block.
* `"signature"` - UNKNOWN
* `"size"` - `t:Explorer.JSONRPC.quantity/0`` of bytes in this block
* `"stateRoot" - `t:Explorer.JSONRPC.hash/0` of the root of the final state
* `"size"` - `t:EthereumJSONRPC.quantity/0`` of bytes in this block
* `"stateRoot" - `t:EthereumJSONRPC.hash/0` of the root of the final state
[trie](https://github.com/ethereum/wiki/wiki/Patricia-Tree) of the block.
* `"step"` - UNKNOWN
* `"timestamp"`: the unix timestamp as a `t:Explorer.JSONRPC.quantity/0`` for when the block was collated.
* `"totalDifficulty" - `t:Explorer.JSONRPC.quantity/0`` of the total difficulty of the chain until this block.
* `"transactions"` - `t:list/0` of `t:Explorer.JSONRPC.Transaction.t/0`.
* `"transactionsRoot" - `t:Explorer.JSONRPC.hash/0` of the root of the transaction
* `"timestamp"`: the unix timestamp as a `t:EthereumJSONRPC.quantity/0`` for when the block was collated.
* `"totalDifficulty" - `t:EthereumJSONRPC.quantity/0`` of the total difficulty of the chain until this block.
* `"transactions"` - `t:list/0` of `t:EthereumJSONRPC.Transaction.t/0`.
* `"transactionsRoot" - `t:EthereumJSONRPC.hash/0` of the root of the transaction
[trie](https://github.com/ethereum/wiki/wiki/Patricia-Tree) of the block.
* `uncles`: `t:list/0` of
[uncles](https://bitcoin.stackexchange.com/questions/39329/in-ethereum-what-is-an-uncle-block)
`t:Explorer.JSONRPC.hash/0`.
`t:EthereumJSONRPC.hash/0`.
"""
@type t :: %{String.t() => JSONRPC.data() | JSONRPC.hash() | JSONRPC.quantity() | nil}
@type t :: %{String.t() => EthereumJSONRPC.data() | EthereumJSONRPC.hash() | EthereumJSONRPC.quantity() | nil}
@doc """
Converts `t:elixir/0` format to params used in `Explorer.Chain`.
iex> Explorer.JSONRPC.Block.elixir_to_params(
iex> EthereumJSONRPC.Block.elixir_to_params(
...> %{
...> "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
...> "difficulty" => 340282366920938463463374607431465537093,
@ -125,9 +125,9 @@ defmodule Explorer.JSONRPC.Block do
end
@doc """
Get `t:Explorer.JSONRPC.Transactions.elixir/0` from `t:elixir/0`
Get `t:EthereumJSONRPC.Transactions.elixir/0` from `t:elixir/0`
iex> Explorer.JSONRPC.Block.elixir_to_transactions(
iex> EthereumJSONRPC.Block.elixir_to_transactions(
...> %{
...> "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
...> "difficulty" => 340282366920938463463374607431768211454,
@ -211,7 +211,7 @@ defmodule Explorer.JSONRPC.Block do
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0` and the timestamps to `t:DateTime.t/0`
iex> Explorer.JSONRPC.Block.to_elixir(
iex> EthereumJSONRPC.Block.to_elixir(
...> %{
...> "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
...> "difficulty" => "0xfffffffffffffffffffffffffffffffe",
@ -278,7 +278,7 @@ defmodule Explorer.JSONRPC.Block do
end
# double check that no new keys are being missed by requiring explicit match for passthrough
# `t:Explorer.JSONRPC.address/0` and `t:Explorer.JSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# hash format
defp entry_to_elixir({key, _} = entry)
when key in ~w(author extraData hash logsBloom miner parentHash receiptsRoot sealFields sha3Uncles signature

@ -1,10 +1,10 @@
defmodule Explorer.JSONRPC.Blocks do
defmodule EthereumJSONRPC.Blocks do
@moduledoc """
Blocks format as returned by [`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash)
and [`eth_getBlockByNumber`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber) from batch requests.
"""
alias Explorer.JSONRPC.{Block, Transactions}
alias EthereumJSONRPC.{Block, Transactions}
@type elixir :: [Block.elixir()]
@type t :: [Block.t()]
@ -12,7 +12,7 @@ defmodule Explorer.JSONRPC.Blocks do
@doc """
Converts `t:elixir/0` elements to params used by `Explorer.Chain.Block.changeset/2`.
iex> Explorer.JSONRPC.Blocks.elixir_to_params(
iex> EthereumJSONRPC.Blocks.elixir_to_params(
...> [
...> %{
...> "author" => "0x0000000000000000000000000000000000000000",
@ -64,9 +64,9 @@ defmodule Explorer.JSONRPC.Blocks do
end
@doc """
Extracts the `t:Explorer.JSONRPC.Transactions.elixir/0` from the `t:elixir/0`.
Extracts the `t:EthereumJSONRPC.Transactions.elixir/0` from the `t:elixir/0`.
iex> Explorer.JSONRPC.Blocks.elixir_to_transactions([
iex> EthereumJSONRPC.Blocks.elixir_to_transactions([
...> %{
...> "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
...> "difficulty" => 340282366920938463463374607431768211454,
@ -150,7 +150,7 @@ defmodule Explorer.JSONRPC.Blocks do
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0` and the timestamps to `t:DateTime.t/0`
iex> Explorer.JSONRPC.Blocks.to_elixir(
iex> EthereumJSONRPC.Blocks.to_elixir(
...> [
...> %{
...> "author" => "0x0000000000000000000000000000000000000000",

@ -1,29 +1,29 @@
defmodule Explorer.JSONRPC.Log do
defmodule EthereumJSONRPC.Log do
@moduledoc """
Log included in return from
[`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt).
"""
import Explorer.JSONRPC, only: [quantity_to_integer: 1]
import EthereumJSONRPC, only: [quantity_to_integer: 1]
@type elixir :: %{String.t() => String.t() | [String.t()] | non_neg_integer()}
@typedoc """
* `"address"` - `t:Explorer.JSONRPC.address/0` from which event originated.
* `"blockHash"` - `t:Explorer.JSONRPC.hash/0` of the block this transaction is in.
* `"blockNumber"` - `t:Explorer.JSONRPC.quantity/0` for the block number this transaction is in.
* `"address"` - `t:EthereumJSONRPC.address/0` from which event originated.
* `"blockHash"` - `t:EthereumJSONRPC.hash/0` of the block this transaction is in.
* `"blockNumber"` - `t:EthereumJSONRPC.quantity/0` for the block number this transaction is in.
* `"data"` - Data containing non-indexed log parameter
* `"logIndex"` - `t:Explorer.JSONRPC.quantity/0` of the event index positon in the block.
* `"logIndex"` - `t:EthereumJSONRPC.quantity/0` of the event index positon in the block.
* `"topics"` - `t:list/0` of at most 4 32-byte topics. Topic 1-3 contains indexed parameters of the log.
* `"transactionHash"` - `t:Explorer.JSONRPC.hash/0` of the transaction
* `"transactionIndex"` - `t:Explorer.JSONRPC.quantity/0` for the index of the transaction in the block.
* `"transactionHash"` - `t:EthereumJSONRPC.hash/0` of the transaction
* `"transactionIndex"` - `t:EthereumJSONRPC.quantity/0` for the index of the transaction in the block.
"""
@type t :: %{String.t() => String.t() | [String.t()]}
@doc """
Converts `t:elixir/0` format to params used in `Explorer.Chain`.
iex> Explorer.JSONRPC.Log.elixir_to_params(
iex> EthereumJSONRPC.Log.elixir_to_params(
...> %{
...> "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415b",
...> "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
@ -71,7 +71,7 @@ defmodule Explorer.JSONRPC.Log do
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0`.
iex> Explorer.JSONRPC.Log.to_elixir(
iex> EthereumJSONRPC.Log.to_elixir(
...> %{
...> "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415b",
...> "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",

@ -1,10 +1,10 @@
defmodule Explorer.JSONRPC.Logs do
defmodule EthereumJSONRPC.Logs do
@moduledoc """
Collection of logs included in return from
[`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt).
"""
alias Explorer.JSONRPC.Log
alias EthereumJSONRPC.Log
@type elixir :: [Log.elixir()]
@type t :: [Log.t()]

@ -1,16 +1,16 @@
defmodule Explorer.JSONRPC.Parity do
defmodule EthereumJSONRPC.Parity do
@moduledoc """
Ethereum JSONRPC methods that are only supported by [Parity](https://wiki.parity.io/).
"""
import Explorer.JSONRPC, only: [config: 1, json_rpc: 2]
import EthereumJSONRPC, only: [config: 1, json_rpc: 2]
alias Explorer.JSONRPC.Parity.Traces
alias EthereumJSONRPC.Parity.Traces
@doc """
Fetches the `t:Explorer.Chain.InternalTransaction.changeset/2` params from the Parity trace URL.
iex> Explorer.JSONRPC.Parity.fetch_internal_transactions([
iex> EthereumJSONRPC.Parity.fetch_internal_transactions([
...> "0x0fa6f723216dba694337f9bb37d8870725655bdf2573526a39454685659e39b1"
...> ])
{:ok,

@ -1,16 +1,16 @@
defmodule Explorer.JSONRPC.Parity.Trace do
defmodule EthereumJSONRPC.Parity.Trace do
@moduledoc """
Trace returned by
[`trace_replayTransaction`](https://wiki.parity.io/JSONRPC-trace-module.html#trace_replaytransaction), which is an
extension to the Ethereum JSONRPC standard that is only supported by [Parity](https://wiki.parity.io/).
"""
alias Explorer.JSONRPC.Parity.Trace.{Action, Result}
alias EthereumJSONRPC.Parity.Trace.{Action, Result}
@doc """
Create type traces are generated when a contract is created.
iex> Explorer.JSONRPC.Parity.Trace.elixir_to_params(
iex> EthereumJSONRPC.Parity.Trace.elixir_to_params(
...> %{
...> "action" => %{
...> "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
@ -46,7 +46,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
A create can fail due to a Bad Instruction in the `init` that is meant to form the `code` of the contract
iex> Explorer.JSONRPC.Parity.Trace.elixir_to_params(
iex> EthereumJSONRPC.Parity.Trace.elixir_to_params(
...> %{
...> "action" => %{
...> "from" => "0x78a42d3705fb3c26a4b54737a784bf064f0815fb",
@ -76,7 +76,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
Call type traces are generated when a method is called. Calls are further divided by call type.
iex> Explorer.JSONRPC.Parity.Trace.elixir_to_params(
iex> EthereumJSONRPC.Parity.Trace.elixir_to_params(
...> %{
...> "action" => %{
...> "callType" => "call",
@ -113,7 +113,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
Calls can error and be reverted
iex> Explorer.JSONRPC.Parity.Trace.elixir_to_params(
iex> EthereumJSONRPC.Parity.Trace.elixir_to_params(
...> %{
...> "action" => %{
...> "callType" => "call",
@ -153,7 +153,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
| `"balance"` | `:value` |
| `"refundAddress"` | `:to_address_hash` |
iex> Explorer.JSONRPC.Parity.Trace.elixir_to_params(
iex> EthereumJSONRPC.Parity.Trace.elixir_to_params(
...> %{
...> "action" => %{
...> "address" => "0xa7542d78b9a0be6147536887e0065f16182d294b",
@ -251,7 +251,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0`.
iex> Explorer.JSONRPC.Parity.Trace.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.to_elixir(
...> %{
...> "action" => %{
...> "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
@ -293,7 +293,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
The caller must put `"index"` and `"transactionHash"` into the incoming map, as Parity itself does not include that
information, but it is needed to locate the trace in history fully.
iex> Explorer.JSONRPC.Parity.Trace.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.to_elixir(
...> %{
...> "action" => %{
...> "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
@ -316,7 +316,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
`"suicide"` `"type"` traces are different in that they have a `nil` `"result"`. This is because the `"result"` key
is used to indicate success from Parity.
iex> Explorer.JSONRPC.Parity.Trace.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.to_elixir(
...> %{
...> "action" => %{
...> "address" => "0xa7542d78b9a0be6147536887e0065f16182d294b",
@ -347,7 +347,7 @@ defmodule Explorer.JSONRPC.Parity.Trace do
A call type trace can error and be reverted.
iex> Explorer.JSONRPC.Parity.Trace.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.to_elixir(
...> %{
...> "action" => %{
...> "callType" => "call",

@ -1,14 +1,14 @@
defmodule Explorer.JSONRPC.Parity.Trace.Action do
defmodule EthereumJSONRPC.Parity.Trace.Action do
@moduledoc """
The action that was peformed in a `t:Explorer.JSONRPC.Parity.Trace.t/0`
The action that was peformed in a `t:EthereumJSONRPC.Parity.Trace.t/0`
"""
import Explorer.JSONRPC, only: [quantity_to_integer: 1]
import EthereumJSONRPC, only: [quantity_to_integer: 1]
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0`.
iex> Explorer.JSONRPC.Parity.Trace.Action.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.Action.to_elixir(
...> %{
...> "from" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
...> "gas" => "0x462534",
@ -24,9 +24,9 @@ defmodule Explorer.JSONRPC.Parity.Trace.Action do
}
For a suicide, the `"balance"` is converted to a `t:non_neg_integer/0` while the `"address"` and `"refundAddress"`
`t:Explorer.JSONRPC.hash/0` pass through.
`t:EthereumJSONRPC.hash/0` pass through.
iex> Explorer.JSONRPC.Parity.Trace.Action.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.Action.to_elixir(
...> %{
...> "address" => "0xa7542d78b9a0be6147536887e0065f16182d294b",
...> "balance" => "0x0",

@ -1,14 +1,14 @@
defmodule Explorer.JSONRPC.Parity.Trace.Result do
defmodule EthereumJSONRPC.Parity.Trace.Result do
@moduledoc """
The result of performing the `t:Explorer.JSONRPC.Parity.Action.t/0` in a `t:Explorer.JSONRPC.Parity.Trace.t/0`.
The result of performing the `t:EthereumJSONRPC.Parity.Action.t/0` in a `t:EthereumJSONRPC.Parity.Trace.t/0`.
"""
import Explorer.JSONRPC, only: [quantity_to_integer: 1]
import EthereumJSONRPC, only: [quantity_to_integer: 1]
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0`.
iex> Explorer.JSONRPC.Parity.Trace.Result.to_elixir(
iex> EthereumJSONRPC.Parity.Trace.Result.to_elixir(
...> %{
...> "address" => "0xffc87239eb0267bc3ca2cd51d12fbf278e02ccb4",
...> "code" => "0x606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100a05780638da5cb5b146100c9578063fdacd5761461011e575b600080fd5b341561007257600080fd5b61009e600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610141565b005b34156100ab57600080fd5b6100b3610224565b6040518082815260200191505060405180910390f35b34156100d457600080fd5b6100dc61022a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561012957600080fd5b61013f600480803590602001909190505061024f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610220578190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b151561020b57600080fd5b6102c65a03f1151561021c57600080fd5b5050505b5050565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102ac57806001819055505b505600a165627a7a72305820a9c628775efbfbc17477a472413c01ee9b33881f550c59d21bee9928835c854b0029",
@ -23,7 +23,7 @@ defmodule Explorer.JSONRPC.Parity.Trace.Result do
`nil` resultscan occur for suicide type traces.
iex> Explorer.JSONRPC.Parity.Trace.Result.to_elixir(nil)
iex> EthereumJSONRPC.Parity.Trace.Result.to_elixir(nil)
nil
"""

@ -1,11 +1,11 @@
defmodule Explorer.JSONRPC.Parity.Traces do
defmodule EthereumJSONRPC.Parity.Traces do
@moduledoc """
Trace returned by
[`trace_replayTransaction`](https://wiki.parity.io/JSONRPC-trace-module.html#trace_replaytransaction), which is an
extension to the Ethereum JSONRPC standard that is only supported by [Parity](https://wiki.parity.io/).
"""
alias Explorer.JSONRPC.Parity.Trace
alias EthereumJSONRPC.Parity.Trace
def elixir_to_params(elixir) when is_list(elixir) do
Enum.map(elixir, &Trace.elixir_to_params/1)

@ -1,37 +1,45 @@
defmodule Explorer.JSONRPC.Receipt do
defmodule EthereumJSONRPC.Receipt do
@moduledoc """
Receipts format as returned by
[`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt).
"""
import Explorer.JSONRPC, only: [quantity_to_integer: 1]
import EthereumJSONRPC, only: [quantity_to_integer: 1]
alias Explorer.Chain.Receipt.Status
alias Explorer.JSONRPC
alias Explorer.JSONRPC.Logs
alias EthereumJSONRPC
alias EthereumJSONRPC.Logs
@type elixir :: %{String.t() => String.t() | non_neg_integer}
@typedoc """
* `"contractAddress"` - The contract `t:Explorer.JSONRPC.address/0` created, if the transaction was a contract
* `"contractAddress"` - The contract `t:EthereumJSONRPC.address/0` created, if the transaction was a contract
creation, otherwise `nil`.
* `"blockHash"` - `t:Explorer.JSONRPC.hash/0` of the block where `"transactionHash"` was in.
* `"blockNumber"` - The block number `t:Explorer.JSONRPC.quanity/0`.
* `"cumulativeGasUsed"` - `t:Explorer.JSONRPC.quantity/0` of gas used when this transaction was executed in the
* `"blockHash"` - `t:EthereumJSONRPC.hash/0` of the block where `"transactionHash"` was in.
* `"blockNumber"` - The block number `t:EthereumJSONRPC.quanity/0`.
* `"cumulativeGasUsed"` - `t:EthereumJSONRPC.quantity/0` of gas used when this transaction was executed in the
block.
* `"gasUsed"` - `t:Explorer.JSONRPC.quantity/0` of gas used by this specific transaction alone.
* `"gasUsed"` - `t:EthereumJSONRPC.quantity/0` of gas used by this specific transaction alone.
* `"logs"` - `t:list/0` of log objects, which this transaction generated.
* `"logsBloom"` - `t:Explorer.JSONRPC.data/0` of 256 Bytes for
* `"logsBloom"` - `t:EthereumJSONRPC.data/0` of 256 Bytes for
[Bloom filter](https://en.wikipedia.org/wiki/Bloom_filter) for light clients to quickly retrieve related logs.
* `"root"` - `t:Explorer.JSONRPC.hash/0` of post-transaction stateroot (pre-Byzantium)
* `"status"` - `t:Explorer.JSONRPC.quantity/0` of either 1 (success) or 0 (failure) (post-Byzantium)
* `"transactionHash"` - `t:Explorer.JSONRPC.hash/0` the transaction.
* `"transactionIndex"` - `t:Explorer.JSONRPC.quantity/0` for the transaction index in the block.
* `"root"` - `t:EthereumJSONRPC.hash/0` of post-transaction stateroot (pre-Byzantium)
* `"status"` - `t:EthereumJSONRPC.quantity/0` of either 1 (success) or 0 (failure) (post-Byzantium)
* `"transactionHash"` - `t:EthereumJSONRPC.hash/0` the transaction.
* `"transactionIndex"` - `t:EthereumJSONRPC.quantity/0` for the transaction index in the block.
"""
@type t :: %{String.t() => JSONRPC.address() | JSONRPC.data() | JSONRPC.hash() | JSONRPC.quantity() | list | nil}
@type t :: %{
String.t() =>
EthereumJSONRPC.address()
| EthereumJSONRPC.data()
| EthereumJSONRPC.hash()
| EthereumJSONRPC.quantity()
| list
| nil
}
@doc """
Get `t:Explorer.JSONRPC.Logs.elixir/0` from `t:elixir/0`
Get `t:EthereumJSONRPC.Logs.elixir/0` from `t:elixir/0`
"""
@spec elixir_to_logs(elixir) :: Logs.elixir()
def elixir_to_logs(%{"logs" => logs}), do: logs
@ -39,7 +47,7 @@ defmodule Explorer.JSONRPC.Receipt do
@doc """
Converts `t:elixir/0` format to params used in `Explorer.Chain`.
iex> Explorer.JSONRPC.Receipt.elixir_to_params(
iex> EthereumJSONRPC.Receipt.elixir_to_params(
...> %{
...> "blockHash" => "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
...> "blockNumber" => 34,
@ -89,7 +97,7 @@ defmodule Explorer.JSONRPC.Receipt do
@doc """
Decodes the stringly typed numerical fields to `t:non_neg_integer/0`.
iex> Explorer.JSONRPC.Receipt.to_elixir(
iex> EthereumJSONRPC.Receipt.to_elixir(
...> %{
...> "blockHash" => "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
...> "blockNumber" => "0x22",
@ -125,7 +133,7 @@ defmodule Explorer.JSONRPC.Receipt do
end
# double check that no new keys are being missed by requiring explicit match for passthrough
# `t:Explorer.JSONRPC.address/0` and `t:Explorer.JSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# hash format
defp entry_to_elixir({key, _} = entry) when key in ~w(blockHash contractAddress logsBloom root transactionHash),
do: entry

@ -1,13 +1,13 @@
defmodule Explorer.JSONRPC.Receipts do
defmodule EthereumJSONRPC.Receipts do
@moduledoc """
Receipts format as returned by
[`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt) from batch
requests.
"""
import Explorer.JSONRPC, only: [config: 1, json_rpc: 2]
import EthereumJSONRPC, only: [config: 1, json_rpc: 2]
alias Explorer.JSONRPC.{Logs, Receipt}
alias EthereumJSONRPC.{Logs, Receipt}
@type elixir :: [Receipt.elixir()]
@type t :: [Receipt.t()]
@ -15,7 +15,7 @@ defmodule Explorer.JSONRPC.Receipts do
@doc """
Extracts logs from `t:elixir/0`
iex> Explorer.JSONRPC.Receipts.elixir_to_logs([
iex> EthereumJSONRPC.Receipts.elixir_to_logs([
...> %{
...> "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
...> "blockNumber" => 37,
@ -67,7 +67,7 @@ defmodule Explorer.JSONRPC.Receipts do
@doc """
Converts each element of `t:elixir/0` to params used by `Explorer.Chain.Receipt.changeset/2`.
iex> Explorer.JSONRPC.Receipts.elixir_to_params([
iex> EthereumJSONRPC.Receipts.elixir_to_params([
...> %{
...> "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
...> "blockNumber" => 37,
@ -136,7 +136,7 @@ defmodule Explorer.JSONRPC.Receipts do
@doc """
Converts stringly typed fields to native Elixir types.
iex> Explorer.JSONRPC.Receipts.to_elixir([
iex> EthereumJSONRPC.Receipts.to_elixir([
...> %{
...> "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
...> "blockNumber" => "0x25",

@ -1,4 +1,4 @@
defmodule Explorer.JSONRPC.Transaction do
defmodule EthereumJSONRPC.Transaction do
@moduledoc """
Transaction format included in the return of
[`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash)
@ -8,45 +8,50 @@ defmodule Explorer.JSONRPC.Transaction do
and [`eth_getTransactionByBlockNumberAndIndex`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblocknumberandindex)
"""
import Explorer.JSONRPC, only: [quantity_to_integer: 1]
import EthereumJSONRPC, only: [quantity_to_integer: 1]
alias Explorer.JSONRPC
alias EthereumJSONRPC
@type elixir :: %{String.t() => JSONRPC.address() | JSONRPC.hash() | String.t() | non_neg_integer() | nil}
@type elixir :: %{
String.t() => EthereumJSONRPC.address() | EthereumJSONRPC.hash() | String.t() | non_neg_integer() | nil
}
@typedoc """
* `"blockHash"` - `t:Explorer.JSONRPC.hash/0` of the block this transaction is in. `nil` when transaction is
* `"blockHash"` - `t:EthereumJSONRPC.hash/0` of the block this transaction is in. `nil` when transaction is
pending.
* `"blockNumber"` - `t:Explorer.JSONRPC.quantity/0` for the block number this transaction is in. `nil` when
* `"blockNumber"` - `t:EthereumJSONRPC.quantity/0` for the block number this transaction is in. `nil` when
transaction is pending.
* `"chainId"` - the chain on which the transaction exists.
* `"condition"` - UNKNOWN
* `"creates"` - `t:Explorer.JSONRPC.address/0` of the created contract, if the transaction creates a contract.
* `"from"` - `t:Explorer.JSONRPC.address/0` of the sender.
* `"gas"` - `t:Explorer.JSONRPC.quantity/0` of gas provided by the sender. This is the max gas that may be used.
* `"creates"` - `t:EthereumJSONRPC.address/0` of the created contract, if the transaction creates a contract.
* `"from"` - `t:EthereumJSONRPC.address/0` of the sender.
* `"gas"` - `t:EthereumJSONRPC.quantity/0` of gas provided by the sender. This is the max gas that may be used.
`gas * gasPrice` is the max fee in wei that the sender is willing to pay for the transaction to be executed.
* `"gasPrice"` - `t:Explorer.JSONRPC.quantity/0` of wei to pay per unit of gas used.
* `"hash"` - `t:Explorer.JSONRPC.hash/0` of the transaction
* `"input"` - `t:Explorer.JSONRPC.data/0` sent along with the transaction, such as input to the contract.
* `"nonce"` - `t:Explorer.JSONRPC.quantity/0` of transactions made by the sender prior to this one.
* `"publicKey"` - `t:Explorer.JSONRPC.hash/0` of the public key of the signer.
* `"r"` - `t:Explorer.JSONRPC.quantity/0` for the R field of the signature.
* `"raw"` - Raw transaction `t:Explorer.JSONRPC.data/0`
* `"standardV"` - `t:Explorer.JSONRPC.quantity/0` for the standardized V (`0` or `1`) field of the signature.
* `"to"` - `t:Explorer.JSONRPC.address/0` of the receiver. `nil` when it is a contract creation transaction.
* `"transactionIndex"` - `t:Explorer.JSONRPC.quantity/0` for the index of the transaction in the block. `nil` when
* `"gasPrice"` - `t:EthereumJSONRPC.quantity/0` of wei to pay per unit of gas used.
* `"hash"` - `t:EthereumJSONRPC.hash/0` of the transaction
* `"input"` - `t:EthereumJSONRPC.data/0` sent along with the transaction, such as input to the contract.
* `"nonce"` - `t:EthereumJSONRPC.quantity/0` of transactions made by the sender prior to this one.
* `"publicKey"` - `t:EthereumJSONRPC.hash/0` of the public key of the signer.
* `"r"` - `t:EthereumJSONRPC.quantity/0` for the R field of the signature.
* `"raw"` - Raw transaction `t:EthereumJSONRPC.data/0`
* `"standardV"` - `t:EthereumJSONRPC.quantity/0` for the standardized V (`0` or `1`) field of the signature.
* `"to"` - `t:EthereumJSONRPC.address/0` of the receiver. `nil` when it is a contract creation transaction.
* `"transactionIndex"` - `t:EthereumJSONRPC.quantity/0` for the index of the transaction in the block. `nil` when
transaction is pending.
* `"v"` - `t:Explorer.JSONRPC.quantity/0` for the V field of the signature.
* `"value"` - `t:Explorer.JSONRPC.quantity/0` of wei transfered
* `"v"` - `t:EthereumJSONRPC.quantity/0` for the V field of the signature.
* `"value"` - `t:EthereumJSONRPC.quantity/0` of wei transfered
"""
@type t :: %{String.t() => JSONRPC.address() | JSONRPC.hash() | JSONRPC.quantity() | String.t() | nil}
@type t :: %{
String.t() =>
EthereumJSONRPC.address() | EthereumJSONRPC.hash() | EthereumJSONRPC.quantity() | String.t() | nil
}
@type params :: %{
block_hash: JSONRPC.hash(),
from_address_hash: JSONRPC.address(),
block_hash: EthereumJSONRPC.hash(),
from_address_hash: EthereumJSONRPC.address(),
gas: non_neg_integer(),
gas_price: non_neg_integer(),
hash: JSONRPC.hash(),
hash: EthereumJSONRPC.hash(),
index: non_neg_integer(),
input: String.t(),
nonce: non_neg_integer(),
@ -54,7 +59,7 @@ defmodule Explorer.JSONRPC.Transaction do
r: non_neg_integer(),
s: non_neg_integer(),
standard_v: 0 | 1,
to_address_hash: JSONRPC.address(),
to_address_hash: EthereumJSONRPC.address(),
v: non_neg_integer(),
value: non_neg_integer()
}
@ -97,9 +102,9 @@ defmodule Explorer.JSONRPC.Transaction do
end
@doc """
Extracts `t:Explorer.JSONRPC.hash/0` from transaction `params`
Extracts `t:EthereumJSONRPC.hash/0` from transaction `params`
iex> Explorer.JSONRPC.Transaction.params_to_hash(
iex> EthereumJSONRPC.Transaction.params_to_hash(
...> %{
...> block_hash: "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
...> gas: 4700000,
@ -129,7 +134,7 @@ defmodule Explorer.JSONRPC.Transaction do
end
# double check that no new keys are being missed by requiring explicit match for passthrough
# `t:Explorer.JSONRPC.address/0` and `t:Explorer.JSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# hash format
# r s standardV and v pass through because they exceed postgres integer limits
defp entry_to_elixir({key, value})

@ -1,11 +1,11 @@
defmodule Explorer.JSONRPC.Transactions do
defmodule EthereumJSONRPC.Transactions do
@moduledoc """
List of transactions format as included in return from
[`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash) and
[`eth_getBlockByNumber`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber).
"""
alias Explorer.JSONRPC.Transaction
alias EthereumJSONRPC.Transaction
@type elixir :: [Transaction.elixir()]
@type t :: [Transaction.t()]
@ -13,7 +13,7 @@ defmodule Explorer.JSONRPC.Transactions do
@doc """
Converts each entry in `elixir` to params used in `Explorer.Chain.Transaction.changeset/2`.
iex> Explorer.JSONRPC.Transactions.elixir_to_params(
iex> EthereumJSONRPC.Transactions.elixir_to_params(
...> [
...> %{
...> "blockHash" => "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
@ -67,7 +67,7 @@ defmodule Explorer.JSONRPC.Transactions do
@doc """
Extract just the `t:Explorer.Chain.Transaction.t/0` `hash` from `params` list elements.
iex> Explorer.JSONRPC.Transactions.params_to_hashes(
iex> EthereumJSONRPC.Transactions.params_to_hashes(
...> [
...> %{
...> block_hash: "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
@ -98,7 +98,7 @@ defmodule Explorer.JSONRPC.Transactions do
@doc """
Decodes stringly typed fields in entries in `transactions`
iex> Explorer.JSONRPC.Transactions.to_elixir([
iex> EthereumJSONRPC.Transactions.to_elixir([
...> %{
...> "blockHash" => "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b47",
...> "blockNumber" => "0x22",

@ -3,31 +3,63 @@ defmodule EthereumJsonrpc.MixProject do
def project do
[
aliases: aliases(Mix.env()),
app: :ethereum_jsonrpc,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps: deps(),
deps_path: "../../deps",
lockfile: "../../mix.lock",
dialyzer: [
plt_add_deps: :transitive,
plt_add_apps: [:mix],
ignore_warnings: "../../.dialyzer-ignore"
],
elixir: "~> 1.6",
lockfile: "../../mix.lock",
preferred_cli_env: [
coveralls: :test,
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test,
dialyzer: :test
],
start_permanent: Mix.env() == :prod,
deps: deps()
test_coverage: [tool: ExCoveralls],
version: "0.1.0"
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
mod: {EthereumJSONRPC.Application, []},
extra_applications: [:logger]
]
end
defp aliases(env) do
env_aliases(env)
end
defp env_aliases(:dev), do: []
defp env_aliases(_env), do: [compile: "compile --warnings-as-errors"]
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
# {:sibling_app_in_umbrella, in_umbrella: true},
# Style Checking
{:credo, "0.9.2", only: [:dev, :test], runtime: false},
# Static Type Checking
{:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false},
# Code coverage
{:excoveralls, "~> 0.8.1", only: [:test]},
# JSONRPC HTTP Post calls
{:httpoison, "~> 1.0", override: true},
# Decode/Encode JSON for JSONRPC
{:jason, "~> 1.0"},
# Convert unix timestamps in JSONRPC to DateTimes
{:timex, "~> 3.1.24"}
]
end
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.BlockTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Block
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.BlocksTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Blocks
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.LogTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Log
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.Parity.Trace.ActionTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Parity.Trace.Action
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.Parity.Trace.ResultTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Parity.Trace.Result
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.Parity.TraceTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Parity.Trace
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.ParityTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Parity
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.ReceiptTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Receipt
end

@ -1,13 +1,13 @@
defmodule Explorer.JSONRPC.ReceiptsTest do
defmodule EthereumJSONRPC.ReceiptsTest do
use ExUnit.Case, async: true
alias Explorer.JSONRPC.Receipts
alias EthereumJSONRPC.Receipts
doctest Receipts
# These are integration tests that depend on the sokol chain being used. sokol can be used with the following config
#
# config :explorer, Explorer.JSONRPC,
# config :explorer, EthereumJSONRPC,
# trace_url: "https://sokol-trace.poa.network",
# url: "https://sokol.poa.network"
#

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.TransactionTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Transaction
end

@ -0,0 +1,5 @@
defmodule EthereumJSONRPC.TransactionsTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Transactions
end

@ -1,8 +0,0 @@
defmodule EthereumJsonrpcTest do
use ExUnit.Case
doctest EthereumJsonrpc
test "greets the world" do
assert EthereumJsonrpc.hello() == :world
end
end

@ -1 +1,7 @@
# https://github.com/CircleCI-Public/circleci-demo-elixir-phoenix/blob/a89de33a01df67b6773ac90adc74c34367a4a2d6/test/test_helper.exs#L1-L3
junit_folder = Mix.Project.build_path() <> "/junit/#{Mix.Project.config()[:app]}"
File.mkdir_p!(junit_folder)
:ok = Application.put_env(:junit_formatter, :report_dir, junit_folder)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()

@ -14,11 +14,6 @@ config :explorer,
ecto_repos: [Explorer.Repo],
coin: "POA"
config :explorer, Explorer.JSONRPC,
http: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :eth]],
trace_url: "https://sokol-trace.poa.network",
url: "https://sokol.poa.network"
config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: 2_000
config :explorer, Explorer.Repo, migration_timestamps: [type: :utc_datetime]

@ -25,7 +25,6 @@ defmodule Explorer.Application do
# Children to start when not testing
defp secondary_children(_) do
[
Explorer.JSONRPC,
Supervisor.child_spec({Task.Supervisor, name: Explorer.TaskSupervisor}, id: Explorer.TaskSupervisor),
Explorer.Indexer.Supervisor,
Explorer.Chain.Statistics.Server,

@ -5,12 +5,9 @@ defmodule Explorer.Indexer.AddressFetcher do
use GenServer
require Logger
alias Explorer.{Chain, JSONRPC}
alias Explorer.Chain.{
Address,
Hash
}
alias EthereumJSONRPC
alias Explorer.Chain
alias Explorer.Chain.{Address, Hash}
@fetch_interval :timer.seconds(3)
@max_batch_size 100
@ -112,7 +109,7 @@ defmodule Explorer.Indexer.AddressFetcher do
end
defp do_fetch_addresses(address_hashes) do
JSONRPC.fetch_balances_by_hash(address_hashes)
EthereumJSONRPC.fetch_balances_by_hash(address_hashes)
end
defp take_batch(queue) do

@ -7,9 +7,10 @@ defmodule Explorer.Indexer.BlockFetcher do
require Logger
alias Explorer.{Chain, Indexer, JSONRPC}
alias EthereumJSONRPC
alias EthereumJSONRPC.Transactions
alias Explorer.{Chain, Indexer}
alias Explorer.Indexer.{AddressFetcher, Sequence}
alias Explorer.JSONRPC.Transactions
# dialyzer thinks that Logger.debug functions always have no_local_return
@dialyzer {:nowarn_function, import_range: 3}
@ -161,7 +162,7 @@ defmodule Explorer.Indexer.BlockFetcher do
hashes
|> Enum.chunk_every(state.internal_transactions_batch_size)
|> Task.async_stream(&JSONRPC.fetch_internal_transactions(&1), stream_opts)
|> Task.async_stream(&EthereumJSONRPC.fetch_internal_transactions(&1), stream_opts)
|> Enum.reduce_while({:ok, []}, fn
{:ok, {:ok, internal_transactions}}, {:ok, acc} -> {:cont, {:ok, acc ++ internal_transactions}}
{:ok, {:error, reason}}, {:ok, _acc} -> {:halt, {:error, reason}}
@ -177,7 +178,7 @@ defmodule Explorer.Indexer.BlockFetcher do
hashes
|> Enum.chunk_every(state.receipts_batch_size)
|> Task.async_stream(&JSONRPC.fetch_transaction_receipts(&1), stream_opts)
|> Task.async_stream(&EthereumJSONRPC.fetch_transaction_receipts(&1), stream_opts)
|> Enum.reduce_while({:ok, %{logs: [], receipts: []}}, fn
{:ok, {:ok, %{logs: logs, receipts: receipts}}}, {:ok, %{logs: acc_logs, receipts: acc_receipts}} ->
{:cont, {:ok, %{logs: acc_logs ++ logs, receipts: acc_receipts ++ receipts}}}
@ -256,7 +257,7 @@ defmodule Explorer.Indexer.BlockFetcher do
# Only public for testing
@doc false
def import_range({block_start, block_end} = range, %{} = state, seq) do
with {:blocks, {:ok, next, result}} <- {:blocks, JSONRPC.fetch_blocks_by_range(block_start, block_end)},
with {:blocks, {:ok, next, result}} <- {:blocks, EthereumJSONRPC.fetch_blocks_by_range(block_start, block_end)},
%{blocks: blocks, transactions: transactions} = result,
cap_seq(seq, next, range, state),
transaction_hashes = Transactions.params_to_hashes(transactions),

@ -1,309 +0,0 @@
defmodule Explorer.JSONRPC do
@moduledoc """
Ethereum JSONRPC client.
## Configuration
Configuration for parity URLs can be provided with the following mix config:
config :explorer, Explorer.JSONRPC,
url: "https://sokol.poa.network",
trace_url: "https://sokol-trace.poa.network",
http: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :eth]]
Note: the tracing node URL is provided separately from `:url`, via `:trace_url`. The trace URL and is used for
`fetch_internal_transactions`, which is only a supported method on tracing nodes. The `:http` option is passed
directly to the HTTP library (`HTTPoison`), which forwards the options down to `:hackney`.
"""
require Logger
alias Explorer.JSONRPC.{Blocks, Parity, Receipts, Transactions}
@typedoc """
Truncated 20-byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash encoded as a hexadecimal number in a
`String.t`.
"""
@type address :: String.t()
@typedoc """
Binary data encoded as a single hexadecimal number in a `String.t`
"""
@type data :: String.t()
@typedoc """
A full 32-byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash encoded as a hexadecimal number in a `String.t`
## Example
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
"""
@type hash :: String.t()
@typedoc """
8 byte [KECCAK-256](https://en.wikipedia.org/wiki/SHA-3) hash of the proof-of-work.
"""
@type nonce :: String.t()
@typedoc """
A number encoded as a hexadecimal number in a `String.t`
## Example
"0x1b4"
"""
@type quantity :: String.t()
@typedoc """
Unix timestamp encoded as a hexadecimal number in a `String.t`
"""
@type timestamp :: String.t()
def child_spec(_opts) do
:hackney_pool.child_spec(:eth, recv_timeout: 60_000, timeout: 60_000, max_connections: 1000)
end
@doc """
Lists changes for a given filter subscription.
"""
def check_for_updates(filter_id) do
request = %{
"id" => filter_id,
"jsonrpc" => "2.0",
"method" => "eth_getFilterChanges",
"params" => [filter_id]
}
json_rpc(request, config(:url))
end
@doc """
Fetches configuration for this module under `key`
Configuration can be set a compile time using `config`
config :explorer, Explorer.JSONRRPC, key: value
Configuration can be set a runtime using `Application.put_env/3`
Application.put_env(:explorer, Explorer.JSONRPC, key: value)
"""
def config(key) do
:explorer
|> Application.fetch_env!(__MODULE__)
|> Keyword.fetch!(key)
end
@doc """
Fetches address balances by address hashes.
"""
def fetch_balances_by_hash(address_hashes) do
batched_requests =
for hash <- address_hashes do
%{
"id" => hash,
"jsonrpc" => "2.0",
"method" => "eth_getBalance",
"params" => [hash, "latest"]
}
end
batched_requests
|> json_rpc(config(:url))
|> handle_balances()
end
defp handle_balances({:ok, results}) do
native_results =
for response <- results, into: %{} do
{response["id"], hexadecimal_to_integer(response["result"])}
end
{:ok, native_results}
end
defp handle_balances({:error, _reason} = err), do: err
@doc """
Fetches blocks by block hashes.
Transaction data is included for each block.
"""
def fetch_blocks_by_hash(block_hashes) do
batched_requests =
for block_hash <- block_hashes do
%{
"id" => block_hash,
"jsonrpc" => "2.0",
"method" => "eth_getBlockByHash",
"params" => [block_hash, true]
}
end
batched_requests
|> json_rpc(config(:url))
|> handle_get_block_by_number()
|> case do
{:ok, _next, results} -> {:ok, results}
{:error, reason} -> {:error, reason}
end
end
@doc """
Fetches blocks by block number range.
"""
def fetch_blocks_by_range(block_start, block_end) do
block_start
|> build_batch_get_block_by_number(block_end)
|> json_rpc(config(:url))
|> handle_get_block_by_number()
end
@doc """
Fetches internal transactions from client-specific API.
"""
def fetch_internal_transactions(hashes) when is_list(hashes) do
Parity.fetch_internal_transactions(hashes)
end
def fetch_transaction_receipts(hashes) when is_list(hashes) do
Receipts.fetch(hashes)
end
@doc """
1. POSTs JSON `payload` to `url`
2. Decodes the response
3. Handles the response
## Returns
* Handled response
* `{:error, reason}` if POST failes
"""
def json_rpc(payload, url) do
json = encode_json(payload)
headers = [{"Content-Type", "application/json"}]
case HTTPoison.post(url, json, headers, config(:http)) do
{:ok, %HTTPoison.Response{body: body, status_code: code}} ->
body |> decode_json(payload, url) |> handle_response(code)
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
@doc """
Creates a filter subscription that can be polled for retreiving new blocks.
"""
def listen_for_new_blocks do
id = DateTime.utc_now() |> DateTime.to_unix()
request = %{
"id" => id,
"jsonrpc" => "2.0",
"method" => "eth_newBlockFilter",
"params" => []
}
json_rpc(request, config(:url))
end
@doc """
Converts `t:nonce/0` to `t:non_neg_integer/0`
"""
def nonce_to_integer(nonce) do
hexadecimal_to_integer(nonce)
end
@doc """
Converts `t:quantity/0` to `t:non_neg_integer/0`.
"""
def quantity_to_integer(quantity) do
hexadecimal_to_integer(quantity)
end
@doc """
Converts `t:timestamp/0` to `t:DateTime.t/0`
"""
def timestamp_to_datetime(timestamp) do
timestamp
|> hexadecimal_to_integer()
|> Timex.from_unix()
end
defp build_batch_get_block_by_number(block_start, block_end) do
for current <- block_start..block_end do
%{
"id" => current,
"jsonrpc" => "2.0",
"method" => "eth_getBlockByNumber",
"params" => [int_to_hash_string(current), true]
}
end
end
defp encode_json(data), do: Jason.encode_to_iodata!(data)
defp decode_json(body, posted_payload, url) do
Jason.decode!(body)
rescue
Jason.DecodeError ->
Logger.error("""
failed to decode json payload:
url: #{inspect(url)}
body: #{inspect(body)}
posted payload: #{inspect(posted_payload)}
""")
raise("bad jason")
end
defp handle_get_block_by_number({:ok, results}) do
{blocks, next} =
Enum.reduce(results, {[], :more}, fn
%{"result" => nil}, {blocks, _} -> {blocks, :end_of_chain}
%{"result" => %{} = block}, {blocks, next} -> {[block | blocks], next}
end)
elixir_blocks = Blocks.to_elixir(blocks)
elixir_transactions = Blocks.elixir_to_transactions(elixir_blocks)
blocks_params = Blocks.elixir_to_params(elixir_blocks)
transactions_params = Transactions.elixir_to_params(elixir_transactions)
{:ok, next,
%{
blocks: blocks_params,
transactions: transactions_params
}}
end
defp handle_get_block_by_number({:error, reason}) do
{:error, reason}
end
defp handle_response(resp, 200) do
case resp do
[%{} | _] = batch_resp -> {:ok, batch_resp}
%{"error" => error} -> {:error, error}
%{"result" => result} -> {:ok, result}
end
end
defp handle_response(resp, _status) do
{:error, resp}
end
defp hexadecimal_to_integer("0x" <> hexadecimal_digits) do
String.to_integer(hexadecimal_digits, 16)
end
defp int_to_hash_string(number), do: "0x" <> Integer.to_string(number, 16)
end

@ -70,6 +70,8 @@ defmodule Explorer.Mixfile do
# Code coverage
{:excoveralls, "~> 0.8.1", only: [:test]},
{:exvcr, "~> 0.10", only: :test},
# JSONRPC access to Parity for `Explorer.Indexer`
{:ethereum_jsonrpc, in_umbrella: true},
{:httpoison, "~> 1.0", override: true},
{:jason, "~> 1.0"},
{:junit_formatter, ">= 0.0.0", only: [:test], runtime: false},

@ -4,7 +4,6 @@ defmodule Explorer.Indexer.AddressFetcherTest do
use Explorer.DataCase, async: false
alias Explorer.Chain.Address
alias Explorer.JSONRPC
alias Explorer.Indexer.AddressFetcher
@hash %Explorer.Chain.Hash{
@ -13,7 +12,6 @@ defmodule Explorer.Indexer.AddressFetcherTest do
}
setup do
start_supervised!({JSONRPC, []})
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
:ok

@ -5,7 +5,6 @@ defmodule Explorer.Indexer.BlockFetcherTest do
import ExUnit.CaptureLog
alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Receipt, Transaction}
alias Explorer.JSONRPC
alias Explorer.Indexer.{BlockFetcher, Sequence}
@tag capture_log: true
@ -32,7 +31,6 @@ defmodule Explorer.Indexer.BlockFetcherTest do
test "starts fetching blocks from Genesis" do
assert Repo.aggregate(Block, :count, :hash) == 0
start_supervised!({JSONRPC, []})
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!(BlockFetcher)
@ -84,7 +82,6 @@ defmodule Explorer.Indexer.BlockFetcherTest do
setup :state
setup do
start_supervised!({JSONRPC, []})
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
{:ok, state} = BlockFetcher.init(debug_logs: false)

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.BlockTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Block
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.BlocksTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Blocks
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.LogTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Log
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.Parity.Trace.ActionTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Parity.Trace.Action
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.Parity.Trace.ResultTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Parity.Trace.Result
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.Parity.TraceTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Parity.Trace
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.ParityTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Parity
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.ReceiptTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Receipt
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.TransactionTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Transaction
end

@ -1,5 +0,0 @@
defmodule Explorer.JSONRPC.TransactionsTest do
use ExUnit.Case, async: true
doctest Explorer.JSONRPC.Transactions
end

@ -1,7 +1,7 @@
{
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 94.0
"minimum_coverage": 91.2
},
"terminal_options": {
"file_column_width": 120

Loading…
Cancel
Save