Merge branch 'master' into ab-do-not-load-assoc-for-trx-inter-trx-pagination

pull/2065/head
Ayrat Badykov 6 years ago committed by GitHub
commit c64149fcf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 43
      apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
  3. 9
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/contract.ex
  4. 19
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
  5. 7
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  6. 23
      apps/explorer/lib/explorer/token/metadata_retriever.ex
  7. 47
      apps/explorer/test/explorer/token/metadata_retriever_test.exs

@ -45,6 +45,8 @@
- [#2017](https://github.com/poanetwork/blockscout/pull/2017) - fix: fix to/from filters on tx list pages
- [#2008](https://github.com/poanetwork/blockscout/pull/2008) - add new function clause for xDai network beneficiaries
- [#2009](https://github.com/poanetwork/blockscout/pull/2009) - addresses page improvements
- [#2052](https://github.com/poanetwork/blockscout/pull/2052) - allow bytes32 for name and symbol
- [#2047](https://github.com/poanetwork/blockscout/pull/2047) - fix: show creating internal transactions
- [#2014](https://github.com/poanetwork/blockscout/pull/2014) - fix: use better queries for listLogs endpoint
- [#2027](https://github.com/poanetwork/blockscout/pull/2027) - fix: `BlocksTransactionsMismatch` ignoring blocks without transactions

@ -153,6 +153,49 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
end)
end
test "returns internal an transaction that created the address", %{conn: conn} do
address = insert(:address)
transaction =
:transaction
|> insert()
|> with_block(insert(:block, number: 1))
from_internal_transaction =
insert(:internal_transaction,
transaction: transaction,
from_address: address,
index: 1,
block_number: transaction.block_number,
transaction_index: transaction.index
)
to_internal_transaction =
insert(:internal_transaction,
transaction: transaction,
to_address: nil,
created_contract_address: address,
index: 2,
block_number: transaction.block_number,
transaction_index: transaction.index
)
path = address_internal_transaction_path(conn, :index, address, %{"filter" => "to", "type" => "JSON"})
conn = get(conn, path)
internal_transaction_tiles = json_response(conn, 200)["items"]
assert Enum.any?(internal_transaction_tiles, fn tile ->
String.contains?(tile, to_string(to_internal_transaction.transaction_hash)) &&
String.contains?(tile, "data-internal-transaction-index=\"#{to_internal_transaction.index}\"")
end)
refute Enum.any?(internal_transaction_tiles, fn tile ->
String.contains?(tile, to_string(from_internal_transaction.transaction_hash)) &&
String.contains?(tile, "data-internal-transaction-index=\"#{from_internal_transaction.index}\"")
end)
end
test "returns next page of results based on last seen internal transaction", %{conn: conn} do
address = insert(:address)

@ -28,10 +28,11 @@ defmodule EthereumJSONRPC.Contract do
@spec execute_contract_functions([call()], [map()], EthereumJSONRPC.json_rpc_named_arguments()) :: [call_result()]
def execute_contract_functions(requests, abi, json_rpc_named_arguments) do
functions =
parsed_abi =
abi
|> ABI.parse_specification()
|> Enum.into(%{}, &{&1.function, &1})
functions = Enum.into(parsed_abi, %{}, &{&1.function, &1})
requests_with_index = Enum.with_index(requests)
@ -52,13 +53,15 @@ defmodule EthereumJSONRPC.Contract do
|> Enum.into(%{}, &{&1.id, &1})
Enum.map(requests_with_index, fn {%{function_name: function_name}, index} ->
selectors = Enum.filter(parsed_abi, fn p_abi -> p_abi.function == function_name end)
indexed_responses[index]
|> case do
nil ->
{:error, "No result"}
response ->
{^index, result} = Encoder.decode_result(response, functions[function_name])
{^index, result} = Encoder.decode_result(response, selectors)
result
end
end)

@ -35,12 +35,29 @@ defmodule EthereumJSONRPC.Encoder do
@doc """
Given a result from the blockchain, and the function selector, returns the result decoded.
"""
@spec decode_result(map(), %ABI.FunctionSelector{}) ::
@spec decode_result(map(), %ABI.FunctionSelector{} | [%ABI.FunctionSelector{}]) ::
{String.t(), {:ok, any()} | {:error, String.t() | :invalid_data}}
def decode_result(%{error: %{code: code, message: message}, id: id}, _selector) do
{id, {:error, "(#{code}) #{message}"}}
end
def decode_result(result, selectors) when is_list(selectors) do
selectors
|> Enum.map(fn selector ->
try do
decode_result(result, selector)
rescue
_ -> :error
end
end)
|> Enum.find(fn decode ->
case decode do
{_id, {:ok, _}} -> true
_ -> false
end
end)
end
def decode_result(%{id: id, result: result}, function_selector) do
types_list = List.wrap(function_selector.returns)

@ -470,7 +470,12 @@ defmodule Explorer.Chain.InternalTransaction do
from_address_hash, created_contract_address_hash from internal_transactions' table.
"""
def where_address_fields_match(query, address_hash, :to) do
where(query, [t], t.to_address_hash == ^address_hash)
where(
query,
[t],
t.to_address_hash == ^address_hash or
(is_nil(t.to_address_hash) and t.created_contract_address_hash == ^address_hash)
)
end
def where_address_fields_match(query, address_hash, :from) do

@ -22,6 +22,16 @@ defmodule Explorer.Token.MetadataRetriever do
"payable" => false,
"type" => "function"
},
%{
"constant" => true,
"inputs" => [],
"name" => "name",
"outputs" => [
%{"name" => "", "type" => "bytes32"}
],
"payable" => false,
"type" => "function"
},
%{
"constant" => true,
"inputs" => [],
@ -60,6 +70,19 @@ defmodule Explorer.Token.MetadataRetriever do
],
"payable" => false,
"type" => "function"
},
%{
"constant" => true,
"inputs" => [],
"name" => "symbol",
"outputs" => [
%{
"name" => "",
"type" => "bytes32"
}
],
"payable" => false,
"type" => "function"
}
]

@ -426,4 +426,51 @@ defmodule Explorer.Token.MetadataRetrieverTest do
on_exit(fn -> Application.put_env(:explorer, :token_functions_reader_max_retries, original) end)
end
end
test "returns name and symbol when they are bytes32" do
token = insert(:token, contract_address: build(:contract_address))
expect(
EthereumJSONRPC.Mox,
:json_rpc,
1,
fn requests, _opts ->
{:ok,
Enum.map(requests, fn
%{id: id, method: "eth_call", params: [%{data: "0x313ce567", to: _}, "latest"]} ->
%{
id: id,
result: "0x0000000000000000000000000000000000000000000000000000000000000012"
}
%{id: id, method: "eth_call", params: [%{data: "0x06fdde03", to: _}, "latest"]} ->
%{
id: id,
result: "0x4d616b6572000000000000000000000000000000000000000000000000000000"
}
%{id: id, method: "eth_call", params: [%{data: "0x95d89b41", to: _}, "latest"]} ->
%{
id: id,
result: "0x4d4b520000000000000000000000000000000000000000000000000000000000"
}
%{id: id, method: "eth_call", params: [%{data: "0x18160ddd", to: _}, "latest"]} ->
%{
id: id,
result: "0x00000000000000000000000000000000000000000000d3c21bcecceda1000000"
}
end)}
end
)
expected = %{
decimals: 18,
name: "Maker",
symbol: "MKR",
total_supply: 1_000_000_000_000_000_000_000_000
}
assert MetadataRetriever.get_functions_of(token.contract_address_hash) == expected
end
end

Loading…
Cancel
Save