Skip to content

Commit

Permalink
Merge pull request blockscout#4847 from blockscout/np-fix-reqd-contra…
Browse files Browse the repository at this point in the history
…ct-page

Fix read contract page
  • Loading branch information
vbaranov authored and jagdeep sidhu committed Nov 3, 2021
1 parent fd188d1 commit 9578f4e
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 70 deletions.
2 changes: 1 addition & 1 deletion .dialyzer-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -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:447
lib/explorer/smart_contract/reader.ex:461
lib/indexer/fetcher/token_total_supply_on_demand.ex:16
lib/explorer/exchange_rates/source.ex:110
lib/explorer/exchange_rates/source.ex:113
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Current

### Features
- [#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
- [#4777](https://github.com/blockscout/blockscout/pull/4777), [#4791](https://github.com/blockscout/blockscout/pull/4791), [#4799](https://github.com/blockscout/blockscout/pull/4799), [#4847](https://github.com/blockscout/blockscout/pull/4847) - 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
Expand Down
11 changes: 8 additions & 3 deletions apps/explorer/lib/explorer/chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6828,9 +6828,14 @@ defmodule Explorer.Chain do
defp get_implementation_address_hash_basic(proxy_address_hash, abi) do
# 5c60da1b = keccak256(implementation())
implementation_address =
case Reader.query_contract(proxy_address_hash, abi, %{
"5c60da1b" => []
}) do
case Reader.query_contract(
proxy_address_hash,
abi,
%{
"5c60da1b" => []
},
false
) do
%{"5c60da1b" => {:ok, [result]}} -> result
_ -> nil
end
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/lib/explorer/chain/block/reward.ex
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ defmodule Explorer.Chain.Block.Reward do
|> Enum.map(fn {key, _value} -> key end)
|> List.first()

case Reader.query_contract(address, abi, params) do
case Reader.query_contract(address, abi, params, false) do
%{^method_id => {:ok, [result]}} -> result
_ -> @empty_address
end
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/lib/explorer/chain/supply/token_bridge.ex
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ defmodule Explorer.Chain.Supply.TokenBridge do
|> Map.get("type", "")

value =
case Reader.query_contract(address, abi, params) do
case Reader.query_contract(address, abi, params, false) do
%{^method_id => {:ok, [result]}} ->
result

Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/lib/explorer/chain_spec/poa/importer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ defmodule Explorer.ChainSpec.POA.Importer do
|> Enum.map(fn {key, _value} -> key end)
|> List.first()

Reader.query_contract(address, abi, params)
Reader.query_contract(address, abi, params, false)

value =
case Reader.query_contract(address, abi, params) do
case Reader.query_contract(address, abi, params, false) do
%{^method_id => {:ok, [result]}} -> result
_ -> 0
end
Expand Down
90 changes: 52 additions & 38 deletions apps/explorer/lib/explorer/smart_contract/reader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,32 @@ defmodule Explorer.SmartContract.Reader do
)
# => %{"sum" => {:error, "Data overflow encoding int, data `abc` cannot fit in 256 bits"}}
"""
@spec query_verified_contract(Hash.Address.t(), functions(), String.t() | nil, SmartContract.abi()) ::
@spec query_verified_contract(Hash.Address.t(), functions(), String.t() | nil, true | false, SmartContract.abi()) ::
functions_results()
def query_verified_contract(address_hash, functions, from, mabi) do
query_verified_contract_inner(address_hash, functions, mabi, from)
def query_verified_contract(address_hash, functions, from, leave_error_as_map, mabi) do
query_verified_contract_inner(address_hash, functions, mabi, from, leave_error_as_map)
end

@spec query_verified_contract(Hash.Address.t(), functions(), SmartContract.abi() | nil) :: functions_results()
def query_verified_contract(address_hash, functions, mabi \\ nil) do
query_verified_contract_inner(address_hash, functions, mabi, nil)
@spec query_verified_contract(Hash.Address.t(), functions(), true | false, SmartContract.abi() | nil) ::
functions_results()
def query_verified_contract(address_hash, functions, leave_error_as_map, mabi \\ nil) do
query_verified_contract_inner(address_hash, functions, mabi, nil, leave_error_as_map)
end

@spec query_verified_contract_inner(Hash.Address.t(), functions(), SmartContract.abi() | nil, String.t() | nil) ::
@spec query_verified_contract_inner(
Hash.Address.t(),
functions(),
SmartContract.abi() | nil,
String.t() | nil,
true | false
) ::
functions_results()
defp query_verified_contract_inner(address_hash, functions, mabi, from) do
defp query_verified_contract_inner(address_hash, functions, mabi, from, leave_error_as_map) do
contract_address = Hash.to_string(address_hash)

abi = prepare_abi(mabi, address_hash)

query_contract(contract_address, from, abi, functions)
query_contract(contract_address, from, abi, functions, leave_error_as_map)
end

defp prepare_abi(nil, address_hash) do
Expand All @@ -103,20 +110,22 @@ defmodule Explorer.SmartContract.Reader do
@spec query_contract(
String.t(),
term(),
functions()
functions(),
true | false
) :: functions_results()
def query_contract(contract_address, abi, functions) do
query_contract_inner(contract_address, abi, functions, nil, nil, false)
def query_contract(contract_address, abi, functions, leave_error_as_map) do
query_contract_inner(contract_address, abi, functions, nil, nil, leave_error_as_map)
end

@spec query_contract(
String.t(),
String.t() | nil,
term(),
functions()
functions(),
true | false
) :: functions_results()
def query_contract(contract_address, from, abi, functions) do
query_contract_inner(contract_address, abi, functions, nil, from, true)
def query_contract(contract_address, from, abi, functions, leave_error_as_map) do
query_contract_inner(contract_address, abi, functions, nil, from, leave_error_as_map)
end

@spec query_contract_by_block_number(
Expand Down Expand Up @@ -223,7 +232,7 @@ defmodule Explorer.SmartContract.Reader do

abi_with_method_id
|> Enum.filter(&Helper.queriable_method?(&1))
|> Enum.map(&fetch_current_value_from_blockchain(&1, abi_with_method_id, contract_address_hash))
|> Enum.map(&fetch_current_value_from_blockchain(&1, abi_with_method_id, contract_address_hash, false))
end
end

Expand All @@ -239,7 +248,9 @@ defmodule Explorer.SmartContract.Reader do

implementation_abi_with_method_id
|> Enum.filter(&Helper.queriable_method?(&1))
|> Enum.map(&fetch_current_value_from_blockchain(&1, implementation_abi_with_method_id, contract_address_hash))
|> Enum.map(
&fetch_current_value_from_blockchain(&1, implementation_abi_with_method_id, contract_address_hash, false)
)
end
end

Expand Down Expand Up @@ -357,7 +368,7 @@ defmodule Explorer.SmartContract.Reader do
"tuple[#{tuple_types}]"
end

def fetch_current_value_from_blockchain(function, abi, contract_address_hash) do
def fetch_current_value_from_blockchain(function, abi, contract_address_hash, leave_error_as_map) do
values =
case function do
%{"inputs" => []} ->
Expand All @@ -366,7 +377,7 @@ defmodule Explorer.SmartContract.Reader do
outputs = function["outputs"]

contract_address_hash
|> query_verified_contract(%{method_id => normalize_args(args)}, abi)
|> query_verified_contract(%{method_id => normalize_args(args)}, leave_error_as_map, abi)
|> link_outputs_and_values(outputs, method_id)

_ ->
Expand All @@ -379,13 +390,14 @@ defmodule Explorer.SmartContract.Reader do
@doc """
Method performs query of read functions of a smart contract.
`type` could be :proxy or :reqular
if ethereumJSONRPC will return some errors it will represented as map
"""
@spec query_function_with_names(Hash.t(), %{method_id: String.t(), args: [term()] | nil}, atom(), String.t()) :: %{
:names => [any()],
:output => [%{}]
}
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name) do
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type)
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, true)
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name)
%{output: outputs, names: names}
end
Expand All @@ -403,36 +415,38 @@ defmodule Explorer.SmartContract.Reader do
String.t()
) :: %{:names => [any()], :output => [%{}]}
def query_function_with_names(contract_address_hash, %{method_id: method_id, args: args}, type, function_name, from) do
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from)
outputs = query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from, true)
names = parse_names_from_abi(get_abi(contract_address_hash, type), function_name)
%{output: outputs, names: names}
end

@doc """
Fetches the blockchain value of a function that requires arguments.
"""
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom()) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type) do
query_function(contract_address_hash, %{method_id: method_id, args: []}, type)
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), true | false) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, leave_error_as_map) do
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, leave_error_as_map)
end

@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom()) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type) do
query_function_inner(contract_address_hash, method_id, args, type, nil)
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), true | false) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, leave_error_as_map) do
query_function_inner(contract_address_hash, method_id, args, type, nil, leave_error_as_map)
end

@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), String.t() | nil) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, from) do
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, from)
@spec query_function(String.t(), %{method_id: String.t(), args: nil}, atom(), String.t() | nil, true | false) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: nil}, type, from, leave_error_as_map) do
query_function(contract_address_hash, %{method_id: method_id, args: []}, type, from, leave_error_as_map)
end

@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), String.t() | nil) :: [%{}]
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from) do
query_function_inner(contract_address_hash, method_id, args, type, from)
@spec query_function(Hash.t(), %{method_id: String.t(), args: [term()]}, atom(), String.t() | nil, true | false) :: [
%{}
]
def query_function(contract_address_hash, %{method_id: method_id, args: args}, type, from, leave_error_as_map) do
query_function_inner(contract_address_hash, method_id, args, type, from, leave_error_as_map)
end

@spec query_function_inner(Hash.t(), String.t(), [term()], atom(), String.t() | nil) :: [%{}]
defp query_function_inner(contract_address_hash, method_id, args, type, from) do
@spec query_function_inner(Hash.t(), String.t(), [term()], atom(), String.t() | nil, true | false) :: [%{}]
defp query_function_inner(contract_address_hash, method_id, args, type, from, leave_error_as_map) do
abi = get_abi(contract_address_hash, type)

parsed_final_abi =
Expand All @@ -441,7 +455,7 @@ defmodule Explorer.SmartContract.Reader do

%{outputs: outputs, method_id: method_id} = proccess_abi(parsed_final_abi, method_id)

query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id)
query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id, leave_error_as_map)
end

defp proccess_abi(nil, _method_id), do: nil
Expand All @@ -454,9 +468,9 @@ defmodule Explorer.SmartContract.Reader do
%{outputs: outputs, method_id: method_id}
end

defp query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id) do
defp query_contract_and_link_outputs(contract_address_hash, args, from, abi, outputs, method_id, leave_error_as_map) do
contract_address_hash
|> query_verified_contract(%{method_id => normalize_args(args)}, from, abi)
|> query_verified_contract(%{method_id => normalize_args(args)}, from, leave_error_as_map, abi)
|> link_outputs_and_values(outputs, method_id)
end

Expand Down
24 changes: 17 additions & 7 deletions apps/explorer/lib/explorer/staking/contract_state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,28 @@ defmodule Explorer.Staking.ContractState do
"2d21d217" => {:ok, [token_contract_address]},
"dfc8bf4e" => {:ok, [validator_set_contract_address]}
} =
Reader.query_contract(staking_contract_address, staking_abi, %{
"#{erc_677_token_contract_signature}" => [],
"#{validator_set_contract_signature}" => []
})
Reader.query_contract(
staking_contract_address,
staking_abi,
%{
"#{erc_677_token_contract_signature}" => [],
"#{validator_set_contract_signature}" => []
},
false
)

# 56b54bae = keccak256(blockRewardContract())
block_reward_contract_signature = "56b54bae"

%{"56b54bae" => {:ok, [block_reward_contract_address]}} =
Reader.query_contract(validator_set_contract_address, validator_set_abi, %{
"#{block_reward_contract_signature}" => []
})
Reader.query_contract(
validator_set_contract_address,
validator_set_abi,
%{
"#{block_reward_contract_signature}" => []
},
false
)

state = %__MODULE__{
eth_blocknumber_pull_interval: eth_blocknumber_pull_interval,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
end

def query_contract(contract_address_hash, contract_functions, abi) do
Reader.query_contract(contract_address_hash, abi, contract_functions)
Reader.query_contract(contract_address_hash, abi, contract_functions, false)
end

def fetch_json(uri) when uri in [%{@token_uri => {:ok, [""]}}, %{@uri => {:ok, [""]}}] do
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/lib/explorer/token/metadata_retriever.ex
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ defmodule Explorer.Token.MetadataRetriever do

defp fetch_functions_with_retries(contract_address_hash, contract_functions, accumulator, retries_left)
when retries_left > 0 do
contract_functions_result = Reader.query_contract(contract_address_hash, @contract_abi, contract_functions)
contract_functions_result = Reader.query_contract(contract_address_hash, @contract_abi, contract_functions, false)

functions_with_errors =
Enum.filter(contract_functions_result, fn function ->
Expand Down
22 changes: 16 additions & 6 deletions apps/explorer/lib/explorer/validator/metadata_retriever.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ defmodule Explorer.Validator.MetadataRetriever do

defp fetch_validators_list do
# b7ab4db5 = keccak256(getValidators())
case Reader.query_contract(config(:validators_contract_address), contract_abi("validators.json"), %{
"b7ab4db5" => []
}) do
case Reader.query_contract(
config(:validators_contract_address),
contract_abi("validators.json"),
%{
"b7ab4db5" => []
},
false
) do
%{"b7ab4db5" => {:ok, [validators]}} -> validators
_ -> []
end
Expand All @@ -28,9 +33,14 @@ defmodule Explorer.Validator.MetadataRetriever do
defp fetch_validator_metadata(validator_address) do
# fa52c7d8 = keccak256(validators(address))
%{"fa52c7d8" => {:ok, fields}} =
Reader.query_contract(config(:metadata_contract_address), contract_abi("metadata.json"), %{
"fa52c7d8" => [validator_address]
})
Reader.query_contract(
config(:metadata_contract_address),
contract_abi("metadata.json"),
%{
"fa52c7d8" => [validator_address]
},
false
)

fields
end
Expand Down
Loading

0 comments on commit 9578f4e

Please sign in to comment.