Merge pull request #4799 from blockscout/np-add-errors-decoding-to-the-read-contract-page

Error decoding: continue
pull/4830/head
Victor Baranov 3 years ago committed by GitHub
commit f50f4adbde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .dialyzer-ignore
  2. 2
      CHANGELOG.md
  3. 8
      apps/block_scout_web/assets/js/lib/smart_contract/common_helpers.js
  4. 3
      apps/block_scout_web/assets/js/lib/smart_contract/write.js
  5. 3
      apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
  6. 36
      apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_function_response.html.eex
  7. 2
      apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
  8. 23
      apps/block_scout_web/lib/block_scout_web/views/smart_contract_view.ex
  9. 109
      apps/block_scout_web/priv/gettext/default.pot
  10. 109
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  11. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
  12. 8
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/contract.ex
  13. 22
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
  14. 49
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/encoder_test.exs
  15. 2
      apps/explorer/lib/explorer/chain.ex
  16. 19
      apps/explorer/lib/explorer/smart_contract/reader.ex

@ -19,7 +19,7 @@ lib/block_scout_web/views/layout_view.ex:145: The call 'Elixir.Poison.Parser':'p
lib/block_scout_web/views/layout_view.ex:237: The call 'Elixir.Poison.Parser':'parse!'
lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:21
lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:22
lib/explorer/smart_contract/reader.ex:440
lib/explorer/smart_contract/reader.ex:447
lib/indexer/fetcher/token_total_supply_on_demand.ex:16
lib/explorer/exchange_rates/source.ex:110
lib/explorer/exchange_rates/source.ex:113

@ -1,7 +1,7 @@
## Current
### Features
- [#4777](https://github.com/blockscout/blockscout/pull/4777), [#4791](https://github.com/blockscout/blockscout/pull/4791) - Added decoding revert reason
- [#4777](https://github.com/blockscout/blockscout/pull/4777), [#4791](https://github.com/blockscout/blockscout/pull/4791), [#4799](https://github.com/blockscout/blockscout/pull/4799) - Added decoding revert reason
- [#4776](https://github.com/blockscout/blockscout/pull/4776) - Added view for unsuccessfully fetched values from read functions
- [#4761](https://github.com/blockscout/blockscout/pull/4761) - ERC-1155 support
- [#4739](https://github.com/blockscout/blockscout/pull/4739) - Improve logs and inputs decoding

@ -74,12 +74,16 @@ export const formatTitleAndError = (error) => {
let { message } = error
var title = message && message.split('Error: ').length > 1 ? message.split('Error: ')[1] : message
title = title && title.split('{').length > 1 ? title.split('{')[0].replace(':', '') : title
var txHash = ''
var errorMap = ''
try {
message = message && message.indexOf('{') >= 0 ? JSON.parse(message && message.slice(message.indexOf('{'))).error : ''
errorMap = message && message.indexOf('{') >= 0 ? JSON.parse(message && message.slice(message.indexOf('{'))) : ''
message = errorMap.error || ''
txHash = errorMap.transactionHash || ''
} catch (exception) {
message = ''
}
return { title: title, message: message }
return { title: title, message: message, txHash: txHash }
}
export const getCurrentAccount = () => {

@ -102,7 +102,8 @@ export function callMethod (isWalletEnabled, $functionInputs, explorerChainId, $
methodToCall
.on('error', function (error) {
var titleAndError = formatTitleAndError(error)
openErrorModal(titleAndError.title.length ? titleAndError.title : `Error in sending transaction for method "${functionName}"`, titleAndError.message, false)
var message = titleAndError.message + (titleAndError.txHash ? `<br><a href="/tx/${titleAndError.txHash}">More info</a>` : '')
openErrorModal(titleAndError.title.length ? titleAndError.title : `Error in sending transaction for method "${functionName}"`, message, false)
})
.on('transactionHash', function (txHash) {
onTransactionHash(txHash, $element, functionName)

@ -131,7 +131,8 @@ defmodule BlockScoutWeb.SmartContractController do
function_name: params["function_name"],
method_id: params["method_id"],
outputs: outputs,
names: names
names: names,
smart_contract_address: address_hash
)
else
:error ->

@ -1,10 +1,40 @@
<div class="tile tile-muted tile-function-response monospace">
<pre>
[ <strong><%= @function_name %></strong> method Response ]
[ <strong><%= @function_name %></strong> <%= gettext("method Response") %> ]
</pre>
<%= case @outputs do %>
<% {:error, message} -> %>
<span class="text-muted"><%=raw(values_with_type(message, :error, nil, 0))%></span>
<% {:error, %{code: code, message: message, data: data}} -> %>
<% revert_reason = Chain.format_revert_reason_message(data) %>
<%= case decode_revert_reason(@smart_contract_address, revert_reason) do %>
<% {:ok, _identifier, text, mapping} -> %>
<pre><%= raw(values_with_type(text, :error, nil)) %></pre>
<div style="padding-left: 20px">
<%= for {name, type, value} <- mapping do %>
<pre><span class="text-muted"><%= raw(values_with_type(value, type, name, 1)) %></span></pre>
<% end %>
</div>
<% {:error, _contract_verified, []} -> %>
<% decoded_revert_reason = decode_hex_revert_reason(revert_reason) %>
<pre><span class="text-muted"><div style="padding-left: 20px"><%= "(#{code}) #{message} (#{if String.valid?(decoded_revert_reason), do: decoded_revert_reason, else: revert_reason})" %></div></span></pre>
<% {:error, _contract_verified, candidates} -> %>
<% {:ok, _identifier, text, mapping} = Enum.at(candidates, 0) %>
<pre><%= raw(values_with_type(text, :error, nil)) %></pre>
<div style="padding-left: 20px">
<%= for {name, type, value} <- mapping do %>
<pre><span class="text-muted"><%= raw(values_with_type(value, type, name, 1)) %></span></pre>
<% end %>
</div>
<% _ -> %>
<% decoded_revert_reason = decode_hex_revert_reason(revert_reason) %>
<pre><span class="text-muted"><div style="padding-left: 20px"><%= "(#{code}) #{message} (#{if String.valid?(decoded_revert_reason), do: decoded_revert_reason, else: revert_reason})" %></div></span></pre>
<% end %>
<% {:error, %{code: code, message: message}} -> %>
<pre><div style="padding-left: 20px">(error) : <%= "(#{code}) #{message}" %></div></pre>
<% {:error, error} -> %>
<pre><div style="padding-left: 20px">(error) : <%= error %></div></pre>
<% _ -> %>
<pre>
[<%= for {item, index} <- Enum.with_index(@outputs) do %>
<%= if named_argument?(item) do %><span class="function-response-item"><%= item["name"] %></span><% end %>
<span class="text-muted"><%= raw(values_with_type(item["value"], item["type"], fetch_name(@names, index), 0)) %></span>

@ -129,7 +129,7 @@
<%= gettext "Revert reason" %> </dt>
<dd class="col-sm-9 col-lg-10">
<%= case BlockScoutWeb.TransactionView.transaction_revert_reason(@transaction) do %>
<% {:error, :contract_not_verified, candidates} when candidates != [] -> %>
<% {:error, _contract_not_verified, candidates} when candidates != [] -> %>
<% {:ok, method_id, text, mapping} = Enum.at(candidates, 0) %>
<%= render(BlockScoutWeb.TransactionView, "_decoded_input_body.html", method_id: method_id, text: text, mapping: mapping, error: true) %>
<% {:ok, method_id, text, mapping} -> %>

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.SmartContractView do
use BlockScoutWeb, :view
alias Explorer.Chain
alias Explorer.Chain.Address
alias Explorer.Chain.{Address, Transaction}
alias Explorer.Chain.Hash.Address, as: HashAddress
alias Explorer.SmartContract.Helper
@ -122,7 +122,7 @@ defmodule BlockScoutWeb.SmartContractView do
def values_with_type(value, type, names, index, _components),
do: render_type_value(type, binary_to_utf_string(value), fetch_name(names, index))
def values_with_type(value, :error, _components), do: render_type_value("error", value, nil)
def values_with_type(value, :error, _components), do: render_type_value("error", value, "error")
defp fetch_name(nil, _index), do: nil
@ -346,4 +346,23 @@ defmodule BlockScoutWeb.SmartContractView do
type
end
end
def decode_revert_reason(to_address, revert_reason) do
smart_contract = Chain.address_hash_to_smart_contract(to_address)
Transaction.decoded_revert_reason(
%Transaction{to_address: %{smart_contract: smart_contract}, hash: to_address},
revert_reason
)
end
def decode_hex_revert_reason(hex_revert_reason) do
case Integer.parse(hex_revert_reason, 16) do
{number, ""} ->
:binary.encode_unsigned(number)
_ ->
hex_revert_reason
end
end
end

@ -456,6 +456,11 @@ msgstr ""
msgid "Burnt Fees"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:65
msgid "CRC Worth"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_csv_export_button.html.eex:2
msgid "CSV"
@ -987,6 +992,11 @@ msgstr ""
msgid "EIP-1167"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:214
msgid "ERC-1155 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:212
msgid "ERC-20 "
@ -1050,6 +1060,11 @@ msgstr ""
msgid "Epochs range(s) or enum, e.g.: 5-9,23-27,47,50"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:10
msgid "Error"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:33
msgid "Error rendering value"
@ -1135,12 +1150,29 @@ msgstr ""
msgid "Favorites"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:245
msgid "Fetching gas used..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_balance_card.html.eex:28
#: lib/block_scout_web/templates/address/_balance_dropdown.html.eex:7
msgid "Fetching tokens..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:208
#: lib/block_scout_web/templates/address/overview.html.eex:212
msgid "Fetching transactions..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:227
#: lib/block_scout_web/templates/address/overview.html.eex:231
msgid "Fetching transfers..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/admin/dashboard/index.html.eex:16
msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches."
@ -1407,6 +1439,11 @@ msgstr ""
msgid "List of token transferred in the transaction."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:22
msgid "Loading chart..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:295
@ -1574,6 +1611,11 @@ msgstr ""
msgid "N/A"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:110
msgid "N/A bytes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:59 lib/block_scout_web/templates/log/_data_decoded_view.html.eex:4
@ -1631,6 +1673,11 @@ msgstr ""
msgid "Nonce"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/inventory/_token.html.eex:11
msgid "Not unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:202
msgid "Number of transactions related to this address."
@ -2006,6 +2053,11 @@ msgstr ""
msgid "Shows the tokens held in the address (includes ERC-20, ERC-721 and ERC-1155)."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:66
msgid "Shows the total CRC balance in the address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:45
msgid "Shows total assets held in the address"
@ -3134,6 +3186,11 @@ msgstr ""
msgid "is not a valid transaction hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_function_response.html.eex:3
msgid "method Response"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_pagination_container.html.eex:41
msgid "of"
@ -3181,55 +3238,3 @@ msgstr ""
#: lib/block_scout_web/templates/stakes/_stakes_modal_delegators_list.html.eex:18
msgid "validator"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:214
msgid "ERC-1155 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/inventory/_token.html.eex:11
msgid "Not unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:10
msgid "Error"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:65
msgid "CRC Worth"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:66
msgid "Shows the total CRC balance in the address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:110
msgid "N/A bytes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:245
msgid "Fetching gas used..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:208
#: lib/block_scout_web/templates/address/overview.html.eex:212
msgid "Fetching transactions..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:227
#: lib/block_scout_web/templates/address/overview.html.eex:231
msgid "Fetching transfers..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:22
msgid "Loading chart..."
msgstr ""

@ -456,6 +456,11 @@ msgstr ""
msgid "Burnt Fees"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:65
msgid "CRC Worth"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_csv_export_button.html.eex:2
msgid "CSV"
@ -987,6 +992,11 @@ msgstr ""
msgid "EIP-1167"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:214
msgid "ERC-1155 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:212
msgid "ERC-20 "
@ -1050,6 +1060,11 @@ msgstr ""
msgid "Epochs range(s) or enum, e.g.: 5-9,23-27,47,50"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:10
msgid "Error"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:33
msgid "Error rendering value"
@ -1135,12 +1150,29 @@ msgstr ""
msgid "Favorites"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:245
msgid "Fetching gas used..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_balance_card.html.eex:28
#: lib/block_scout_web/templates/address/_balance_dropdown.html.eex:7
msgid "Fetching tokens..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:208
#: lib/block_scout_web/templates/address/overview.html.eex:212
msgid "Fetching transactions..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:227
#: lib/block_scout_web/templates/address/overview.html.eex:231
msgid "Fetching transfers..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/admin/dashboard/index.html.eex:16
msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches."
@ -1407,6 +1439,11 @@ msgstr ""
msgid "List of token transferred in the transaction."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:22
msgid "Loading chart..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:295
@ -1574,6 +1611,11 @@ msgstr ""
msgid "N/A"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:110
msgid "N/A bytes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:59 lib/block_scout_web/templates/log/_data_decoded_view.html.eex:4
@ -1631,6 +1673,11 @@ msgstr ""
msgid "Nonce"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/inventory/_token.html.eex:11
msgid "Not unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:202
msgid "Number of transactions related to this address."
@ -2006,6 +2053,11 @@ msgstr ""
msgid "Shows the tokens held in the address (includes ERC-20, ERC-721 and ERC-1155)."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:66
msgid "Shows the total CRC balance in the address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:45
msgid "Shows total assets held in the address"
@ -3134,6 +3186,11 @@ msgstr ""
msgid "is not a valid transaction hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_function_response.html.eex:3
msgid "method Response"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_pagination_container.html.eex:41
msgid "of"
@ -3181,55 +3238,3 @@ msgstr ""
#: lib/block_scout_web/templates/stakes/_stakes_modal_delegators_list.html.eex:18
msgid "validator"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:214
msgid "ERC-1155 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/inventory/_token.html.eex:11
msgid "Not unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:10
msgid "Error"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:65
msgid "CRC Worth"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:66
msgid "Shows the total CRC balance in the address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:110
msgid "N/A bytes"
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address/overview.html.eex:245
msgid "Fetching gas used..."
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address/overview.html.eex:208
#: lib/block_scout_web/templates/address/overview.html.eex:212
msgid "Fetching transactions..."
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address/overview.html.eex:227
#: lib/block_scout_web/templates/address/overview.html.eex:231
msgid "Fetching transfers..."
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:22
msgid "Loading chart..."
msgstr ""

@ -167,9 +167,9 @@ defmodule EthereumJSONRPC do
]}
"""
@spec execute_contract_functions([Contract.call()], [map()], json_rpc_named_arguments) :: [Contract.call_result()]
def execute_contract_functions(functions, abi, json_rpc_named_arguments) do
def execute_contract_functions(functions, abi, json_rpc_named_arguments, leave_error_as_map \\ false) do
if Enum.count(functions) > 0 do
Contract.execute_contract_functions(functions, abi, json_rpc_named_arguments)
Contract.execute_contract_functions(functions, abi, json_rpc_named_arguments, leave_error_as_map)
else
[]
end

@ -26,8 +26,10 @@ defmodule EthereumJSONRPC.Contract do
"""
@type call_result :: {:ok, term()} | {:error, String.t()}
@spec execute_contract_functions([call()], [map()], EthereumJSONRPC.json_rpc_named_arguments()) :: [call_result()]
def execute_contract_functions(requests, abi, json_rpc_named_arguments) do
@spec execute_contract_functions([call()], [map()], EthereumJSONRPC.json_rpc_named_arguments(), true | false) :: [
call_result()
]
def execute_contract_functions(requests, abi, json_rpc_named_arguments, leave_error_as_map \\ false) do
parsed_abi =
abi
|> ABI.parse_specification()
@ -68,7 +70,7 @@ defmodule EthereumJSONRPC.Contract do
response ->
selectors = define_selectors(parsed_abi, method_id)
{^index, result} = Encoder.decode_result(response, selectors)
{^index, result} = Encoder.decode_result(response, selectors, leave_error_as_map)
result
end
end)

@ -45,17 +45,27 @@ defmodule EthereumJSONRPC.Encoder do
@doc """
Given a result from the blockchain, and the function selector, returns the result decoded.
"""
def decode_result(_, _, leave_error_as_map \\ false)
@spec decode_result(map(), %ABI.FunctionSelector{} | [%ABI.FunctionSelector{}]) ::
{String.t(), {:ok, any()} | {:error, String.t() | :invalid_data}}
def decode_result(%{error: %{code: code, data: data, message: message}, id: id}, _selector) do
{id, {:error, "(#{code}) #{message} (#{data})"}}
def decode_result(%{error: %{code: code, data: data, message: message}, id: id}, _selector, leave_error_as_map) do
if leave_error_as_map do
{id, {:error, %{code: code, message: message, data: data}}}
else
{id, {:error, "(#{code}) #{message} (#{data})"}}
end
end
def decode_result(%{error: %{code: code, message: message}, id: id}, _selector) do
{id, {:error, "(#{code}) #{message}"}}
def decode_result(%{error: %{code: code, message: message}, id: id}, _selector, leave_error_as_map) do
if leave_error_as_map do
{id, {:error, %{code: code, message: message}}}
else
{id, {:error, "(#{code}) #{message}"}}
end
end
def decode_result(result, selectors) when is_list(selectors) do
def decode_result(result, selectors, _leave_error_as_map) when is_list(selectors) do
selectors
|> Enum.map(fn selector ->
try do
@ -72,7 +82,7 @@ defmodule EthereumJSONRPC.Encoder do
end)
end
def decode_result(%{id: id, result: result}, function_selector) do
def decode_result(%{id: id, result: result}, function_selector, _leave_error_as_map) do
types_list = List.wrap(function_selector.returns)
decoded_data =

@ -78,6 +78,55 @@ defmodule EthereumJSONRPC.EncoderTest do
{"sum", {:error, "(-32602) Invalid params: Invalid hex: Invalid character 'x' at position 134."}}
end
test "correctly handles the blockchain error response with returning error as map without data" do
result = %{
error: %{
code: -32602,
message: "Invalid params: Invalid hex: Invalid character 'x' at position 134."
},
id: "sum",
jsonrpc: "2.0"
}
selector = %ABI.FunctionSelector{
function: "get",
returns: {:uint, 256},
types: [{:uint, 256}]
}
assert Encoder.decode_result(result, selector, true) ==
{"sum",
{:error,
%{code: -32602, message: "Invalid params: Invalid hex: Invalid character 'x' at position 134."}}}
end
test "correctly handles the blockchain error response with returning error as map with data" do
result = %{
error: %{
code: -32602,
message: "Invalid params: Invalid hex: Invalid character 'x' at position 134.",
data: "0x01"
},
id: "sum",
jsonrpc: "2.0"
}
selector = %ABI.FunctionSelector{
function: "get",
returns: {:uint, 256},
types: [{:uint, 256}]
}
assert Encoder.decode_result(result, selector, true) ==
{"sum",
{:error,
%{
code: -32602,
message: "Invalid params: Invalid hex: Invalid character 'x' at position 134.",
data: "0x01"
}}}
end
test "correctly decodes string types" do
result =
"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000441494f4e00000000000000000000000000000000000000000000000000000000"

@ -3676,7 +3676,7 @@ defmodule Explorer.Chain do
formatted_revert_reason
end
defp format_revert_reason_message(revert_reason) do
def format_revert_reason_message(revert_reason) do
case revert_reason do
@revert_msg_prefix_1 <> rest ->
rest

@ -106,7 +106,7 @@ defmodule Explorer.SmartContract.Reader do
functions()
) :: functions_results()
def query_contract(contract_address, abi, functions) do
query_contract_inner(contract_address, abi, functions, nil, nil)
query_contract_inner(contract_address, abi, functions, nil, nil, false)
end
@spec query_contract(
@ -116,7 +116,7 @@ defmodule Explorer.SmartContract.Reader do
functions()
) :: functions_results()
def query_contract(contract_address, from, abi, functions) do
query_contract_inner(contract_address, abi, functions, nil, from)
query_contract_inner(contract_address, abi, functions, nil, from, true)
end
@spec query_contract_by_block_number(
@ -125,11 +125,11 @@ defmodule Explorer.SmartContract.Reader do
functions(),
non_neg_integer()
) :: functions_results()
def query_contract_by_block_number(contract_address, abi, functions, block_number) do
query_contract_inner(contract_address, abi, functions, block_number, nil)
def query_contract_by_block_number(contract_address, abi, functions, block_number, leave_error_as_map \\ false) do
query_contract_inner(contract_address, abi, functions, block_number, nil, leave_error_as_map)
end
defp query_contract_inner(contract_address, abi, functions, block_number, from) do
defp query_contract_inner(contract_address, abi, functions, block_number, from, leave_error_as_map) do
requests =
functions
|> Enum.map(fn {method_id, args} ->
@ -143,7 +143,7 @@ defmodule Explorer.SmartContract.Reader do
end)
requests
|> query_contracts(abi)
|> query_contracts(abi, [], leave_error_as_map)
|> Enum.zip(requests)
|> Enum.into(%{}, fn {response, request} ->
{request.method_id, response}
@ -169,6 +169,13 @@ defmodule Explorer.SmartContract.Reader do
EthereumJSONRPC.execute_contract_functions(requests, abi, json_rpc_named_arguments)
end
@spec query_contracts([Contract.call()], term(), true | false) :: [Contract.call_result()]
def query_contracts(requests, abi, [], leave_error_as_map) do
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
EthereumJSONRPC.execute_contract_functions(requests, abi, json_rpc_named_arguments, leave_error_as_map)
end
@doc """
List all the smart contract functions with its current value from the
blockchain, following the ABI order.

Loading…
Cancel
Save