Merge pull request #6187 from blockscout/vb-filter-by-time-created-listcontracts-api

Filter by created time of verified contracts in listcontracts API endpoint
pull/6185/head
Victor Baranov 2 years ago committed by GitHub
commit 0733d20287
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 55
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/address_controller.ex
  3. 16
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex
  4. 30
      apps/block_scout_web/lib/block_scout_web/etherscan.ex
  5. 76
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs
  6. 207
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
  7. 27
      apps/explorer/lib/explorer/etherscan/contracts.ex

@ -2,6 +2,7 @@
### Features
- [#6187](https://github.com/blockscout/blockscout/pull/6187) - Filter by created time of verified contracts in listcontracts API endpoint
- [#6092](https://github.com/blockscout/blockscout/pull/6092) - Blockscout Account functionality
- [#6073](https://github.com/blockscout/blockscout/pull/6073) - Add vyper support for rust verifier microservice integration
- [#6111](https://github.com/blockscout/blockscout/pull/6111) - Add Prometheus metrics to indexer

@ -249,11 +249,11 @@ defmodule BlockScoutWeb.API.RPC.AddressController do
%{}
|> put_order_by_direction(params)
|> Helpers.put_pagination_options(params)
|> put_start_block(params)
|> put_end_block(params)
|> put_block(params, "start_block")
|> put_block(params, "end_block")
|> put_filter_by(params)
|> put_start_timestamp(params)
|> put_end_timestamp(params)
|> put_timestamp(params, "start_timestamp")
|> put_timestamp(params, "end_timestamp")
end
@doc """
@ -427,52 +427,39 @@ defmodule BlockScoutWeb.API.RPC.AddressController do
end
end
defp put_start_block(options, params) do
with %{"startblock" => startblock_param} <- params,
{start_block, ""} <- Integer.parse(startblock_param) do
Map.put(options, :start_block, start_block)
else
_ ->
options
end
end
defp put_end_block(options, params) do
with %{"endblock" => endblock_param} <- params,
{end_block, ""} <- Integer.parse(endblock_param) do
Map.put(options, :end_block, end_block)
# sobelow_skip ["DOS.StringToAtom"]
defp put_block(options, params, key) do
with %{^key => block_param} <- params,
{block_number, ""} <- Integer.parse(block_param) do
Map.put(options, String.to_atom(key), block_number)
else
_ ->
options
end
end
# sobelow_skip ["DOS.StringToAtom"]
defp put_filter_by(options, params) do
case params do
%{"filterby" => filter_by} when filter_by in ["from", "to"] ->
Map.put(options, :filter_by, filter_by)
%{"filter_by" => filter_by} when filter_by in ["from", "to"] ->
Map.put(options, String.to_atom("filter_by"), filter_by)
_ ->
options
end
end
defp put_start_timestamp(options, params) do
with %{"starttimestamp" => starttimestamp_param} <- params,
{unix_timestamp, ""} <- Integer.parse(starttimestamp_param),
{:ok, start_timestamp} <- DateTime.from_unix(unix_timestamp) do
Map.put(options, :start_timestamp, start_timestamp)
else
_ ->
options
end
def put_timestamp({:ok, options}, params, timestamp_param_key) do
options = put_timestamp(options, params, timestamp_param_key)
{:ok, options}
end
defp put_end_timestamp(options, params) do
with %{"endtimestamp" => endtimestamp_param} <- params,
{unix_timestamp, ""} <- Integer.parse(endtimestamp_param),
{:ok, end_timestamp} <- DateTime.from_unix(unix_timestamp) do
Map.put(options, :end_timestamp, end_timestamp)
# sobelow_skip ["DOS.StringToAtom"]
def put_timestamp(options, params, timestamp_param_key) do
with %{^timestamp_param_key => timestamp_param} <- params,
{unix_timestamp, ""} <- Integer.parse(timestamp_param),
{:ok, timestamp} <- DateTime.from_unix(unix_timestamp) do
Map.put(options, String.to_atom(timestamp_param_key), timestamp)
else
_ ->
options

@ -4,7 +4,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
require Logger
alias BlockScoutWeb.AddressContractVerificationController, as: VerificationController
alias BlockScoutWeb.API.RPC.Helpers
alias BlockScoutWeb.API.RPC.{AddressController, Helpers}
alias Explorer.Chain
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
alias Explorer.Chain.{Address, Hash, SmartContract}
@ -420,7 +420,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
case Map.get(opts, :filter) do
:verified ->
Contracts.list_verified_contracts(page_size, offset)
Contracts.list_verified_contracts(page_size, offset, opts)
:decompiled ->
not_decompiled_with_version = Map.get(opts, :not_decompiled_with_version)
@ -443,7 +443,9 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
defp add_filters(options, params) do
options
|> add_filter(params)
|> add_not_decompiled_with_version(params)
|> add_param(params, :not_decompiled_with_version)
|> AddressController.put_timestamp(params, "verified_at_start_timestamp")
|> AddressController.put_timestamp(params, "verified_at_end_timestamp")
end
defp add_filter(options, params) do
@ -456,14 +458,14 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
end
end
defp add_not_decompiled_with_version({:ok, options}, params) do
case Map.fetch(params, "not_decompiled_with_version") do
{:ok, value} -> {:ok, Map.put(options, :not_decompiled_with_version, value)}
defp add_param({:ok, options}, params, key) do
case Map.fetch(params, Atom.to_string(key)) do
{:ok, value} -> {:ok, Map.put(options, key, value)}
:error -> {:ok, options}
end
end
defp add_not_decompiled_with_version(options, _params) do
defp add_param(options, _params, _key) do
options
end

@ -1406,12 +1406,12 @@ defmodule BlockScoutWeb.Etherscan do
"A string representing the order by block number direction. Defaults to descending order. Available values: asc, desc"
},
%{
key: "startblock",
key: "start_block",
type: "integer",
description: "A nonnegative integer that represents the starting block number."
},
%{
key: "endblock",
key: "end_block",
type: "integer",
description: "A nonnegative integer that represents the ending block number."
},
@ -1428,7 +1428,7 @@ defmodule BlockScoutWeb.Etherscan do
"A nonnegative integer that represents the maximum number of records to return when paginating. 'page' must be provided in conjunction."
},
%{
key: "filterby",
key: "filter_by",
type: "string",
description: """
A string representing the field to filter by. If none is given
@ -1437,12 +1437,12 @@ defmodule BlockScoutWeb.Etherscan do
"""
},
%{
key: "starttimestamp",
key: "start_timestamp",
type: "unix timestamp",
description: "Represents the starting block timestamp."
},
%{
key: "endtimestamp",
key: "end_timestamp",
type: "unix timestamp",
description: "Represents the ending block timestamp."
}
@ -1499,13 +1499,13 @@ defmodule BlockScoutWeb.Etherscan do
"A string representing the order by block number direction. Defaults to ascending order. Available values: asc, desc. WARNING: Only available if 'address' is provided."
},
%{
key: "startblock",
key: "start_block",
type: "integer",
description:
"A nonnegative integer that represents the starting block number. WARNING: Only available if 'address' is provided."
},
%{
key: "endblock",
key: "end_block",
type: "integer",
description:
"A nonnegative integer that represents the ending block number. WARNING: Only available if 'address' is provided."
@ -1574,12 +1574,12 @@ defmodule BlockScoutWeb.Etherscan do
"A string representing the order by block number direction. Defaults to ascending order. Available values: asc, desc"
},
%{
key: "startblock",
key: "start_block",
type: "integer",
description: "A nonnegative integer that represents the starting block number."
},
%{
key: "endblock",
key: "end_block",
type: "integer",
description: "A nonnegative integer that represents the ending block number."
},
@ -2316,6 +2316,18 @@ defmodule BlockScoutWeb.Etherscan do
type: "string",
description:
"Ensures that none of the returned contracts were decompiled with the provided version. Ignored unless filtering for decompiled contracts."
},
%{
key: "verified_at_start_timestamp",
type: "unix timestamp",
description:
"Represents the starting timestamp when contracts verified. Taking into account only with `verified` filter."
},
%{
key: "verified_at_end_timestamp",
type: "unix timestamp",
description:
"Represents the ending timestamp when contracts verified. Taking into account only with `verified` filter."
}
],
responses: [

@ -1090,7 +1090,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with startblock and endblock params", %{conn: conn} do
test "with start_block and end_block params", %{conn: conn} do
blocks = [_, second_block, third_block, _] = insert_list(4, :block)
address = insert(:address)
@ -1104,8 +1104,8 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"startblock" => "#{second_block.number}",
"endblock" => "#{third_block.number}"
"start_block" => "#{second_block.number}",
"end_block" => "#{third_block.number}"
}
expected_block_numbers = [
@ -1129,7 +1129,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with startblock but without endblock", %{conn: conn} do
test "with start_block but without end_block", %{conn: conn} do
blocks = [_, _, third_block, fourth_block] = insert_list(4, :block)
address = insert(:address)
@ -1143,7 +1143,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"startblock" => "#{third_block.number}"
"start_block" => "#{third_block.number}"
}
expected_block_numbers = [
@ -1167,7 +1167,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with endblock but without startblock", %{conn: conn} do
test "with end_block but without start_block", %{conn: conn} do
blocks = [first_block, second_block, _, _] = insert_list(4, :block)
address = insert(:address)
@ -1181,7 +1181,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"endblock" => "#{second_block.number}"
"end_block" => "#{second_block.number}"
}
expected_block_numbers = [
@ -1205,7 +1205,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "ignores invalid startblock and endblock", %{conn: conn} do
test "ignores invalid start_block and end_block", %{conn: conn} do
blocks = [_, _, _, _] = insert_list(4, :block)
address = insert(:address)
@ -1219,8 +1219,8 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"startblock" => "invalidstart",
"endblock" => "invalidend"
"start_block" => "invalidstart",
"end_block" => "invalidend"
}
assert response =
@ -1234,7 +1234,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with starttimestamp and endtimestamp params", %{conn: conn} do
test "with start_timestamp and end_timestamp params", %{conn: conn} do
now = Timex.now()
timestamp1 = Timex.shift(now, hours: -6)
timestamp2 = Timex.shift(now, hours: -3)
@ -1257,8 +1257,8 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"starttimestamp" => "#{start_timestamp}",
"endtimestamp" => "#{end_timestamp}"
"start_timestamp" => "#{start_timestamp}",
"end_timestamp" => "#{end_timestamp}"
}
expected_block_numbers = [
@ -1282,7 +1282,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with starttimestamp but without endtimestamp", %{conn: conn} do
test "with start_timestamp but without end_timestamp", %{conn: conn} do
now = Timex.now()
timestamp1 = Timex.shift(now, hours: -6)
timestamp2 = Timex.shift(now, hours: -3)
@ -1304,7 +1304,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"starttimestamp" => "#{start_timestamp}"
"start_timestamp" => "#{start_timestamp}"
}
expected_block_numbers = [
@ -1330,7 +1330,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with endtimestamp but without starttimestamp", %{conn: conn} do
test "with end_timestamp but without start_timestamp", %{conn: conn} do
now = Timex.now()
timestamp1 = Timex.shift(now, hours: -6)
timestamp2 = Timex.shift(now, hours: -3)
@ -1352,7 +1352,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"endtimestamp" => "#{end_timestamp}"
"end_timestamp" => "#{end_timestamp}"
}
expected_block_numbers = [
@ -1376,7 +1376,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with filterby=to option", %{conn: conn} do
test "with filter_by=to option", %{conn: conn} do
block = insert(:block)
address = insert(:address)
@ -1390,7 +1390,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"filterby" => "to"
"filter_by" => "to"
}
assert response =
@ -1404,7 +1404,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert :ok = ExJsonSchema.Validator.validate(txlist_schema(), response)
end
test "with filterby=from option", %{conn: conn} do
test "with filter_by=from option", %{conn: conn} do
block = insert(:block)
address = insert(:address)
@ -1421,7 +1421,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
"module" => "account",
"action" => "txlist",
"address" => "#{address.hash}",
"filterby" => "from"
"filter_by" => "from"
}
assert response =
@ -2830,16 +2830,16 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
describe "optional_params/1" do
test "includes valid optional params in the required format" do
params = %{
"startblock" => "100",
"endblock" => "120",
"start_block" => "100",
"end_block" => "120",
"sort" => "asc",
# page number
"page" => "1",
# page size
"offset" => "2",
"filterby" => "to",
"starttimestamp" => "1539186474",
"endtimestamp" => "1539186474"
"filter_by" => "to",
"start_timestamp" => "1539186474",
"end_timestamp" => "1539186474"
}
optional_params = AddressController.optional_params(params)
@ -2875,20 +2875,20 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
assert AddressController.optional_params(params3) == %{}
end
test "'filterby' value can be 'to' or 'from'" do
params1 = %{"filterby" => "to"}
test "'filter_by' value can be 'to' or 'from'" do
params1 = %{"filter_by" => "to"}
optional_params1 = AddressController.optional_params(params1)
assert optional_params1.filter_by == "to"
params2 = %{"filterby" => "from"}
params2 = %{"filter_by" => "from"}
optional_params2 = AddressController.optional_params(params2)
assert optional_params2.filter_by == "from"
params3 = %{"filterby" => "invalid"}
params3 = %{"filter_by" => "invalid"}
assert AddressController.optional_params(params3) == %{}
end
@ -2899,25 +2899,25 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
test "ignores invalid optional params, keeps valid ones" do
params1 = %{
"startblock" => "invalid",
"endblock" => "invalid",
"start_block" => "invalid",
"end_block" => "invalid",
"sort" => "invalid",
"page" => "invalid",
"offset" => "invalid",
"starttimestamp" => "invalid",
"endtimestamp" => "invalid"
"start_timestamp" => "invalid",
"end_timestamp" => "invalid"
}
assert AddressController.optional_params(params1) == %{}
params2 = %{
"startblock" => "4",
"endblock" => "10",
"start_block" => "4",
"end_block" => "10",
"sort" => "invalid",
"page" => "invalid",
"offset" => "invalid",
"starttimestamp" => "invalid",
"endtimestamp" => "invalid"
"start_timestamp" => "invalid",
"end_timestamp" => "invalid"
}
optional_params = AddressController.optional_params(params2)

@ -6,6 +6,66 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
import Mox
def prepare_contracts do
insert(:contract_address)
{:ok, dt_1, _} = DateTime.from_iso8601("2022-09-20 10:00:00Z")
contract_1 =
insert(:smart_contract,
contract_code_md5: "123",
name: "Test 1",
optimization: "1",
compiler_version: "v0.6.8+commit.0bbfe453",
abi: [%{foo: "bar"}],
inserted_at: dt_1
)
insert(:contract_address)
{:ok, dt_2, _} = DateTime.from_iso8601("2022-09-22 10:00:00Z")
contract_2 =
insert(:smart_contract,
contract_code_md5: "12345",
name: "Test 2",
optimization: "0",
compiler_version: "v0.7.5+commit.eb77ed08",
abi: [%{foo: "bar-2"}],
inserted_at: dt_2
)
insert(:contract_address)
{:ok, dt_3, _} = DateTime.from_iso8601("2022-09-24 10:00:00Z")
contract_3 =
insert(:smart_contract,
contract_code_md5: "1234567",
name: "Test 3",
optimization: "1",
compiler_version: "v0.4.26+commit.4563c3fc",
abi: [%{foo: "bar-3"}],
inserted_at: dt_3
)
[contract_1, contract_2, contract_3]
end
def result(contract) do
%{
"ABI" => Jason.encode!(contract.abi),
"Address" => to_string(contract.address_hash),
"CompilerVersion" => contract.compiler_version,
"ContractName" => contract.name,
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}
end
defp result_not_verified(address_hash) do
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(address_hash)
}
end
describe "listcontracts" do
setup do
%{params: %{"module" => "contract", "action" => "listcontracts"}}
@ -47,15 +107,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => Jason.encode!(contract.abi),
"Address" => to_string(contract.address_hash),
"CompilerVersion" => contract.compiler_version,
"ContractName" => contract.name,
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}
]
assert response["result"] == [result(contract)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -71,12 +123,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(address.hash)
}
]
assert response["result"] == [result_not_verified(address.hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -93,12 +140,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(address.hash)
}
]
assert response["result"] == [result_not_verified(address.hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -119,12 +161,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(address.hash)
}
]
assert response["result"] == [result_not_verified(address.hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -141,15 +178,82 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
assert response["result"] == [result(contract)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
test "filtering for only verified contracts in the date range shows only verified contracts in that range", %{
params: params,
conn: conn
} do
[contract_1, contract_2, contract_3] = prepare_contracts()
filter_params =
params
|> Map.put("filter", "verified")
|> Map.put("verified_at_start_timestamp", "1663749418")
|> Map.put("verified_at_end_timestamp", "1663922218")
response =
conn
|> get("/api", filter_params)
|> json_response(200)
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [result(contract_2)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
test "filtering for only verified contracts with start created_at timestamp >= given timestamp shows only verified contracts in that range",
%{
"ABI" => Jason.encode!(contract.abi),
"Address" => to_string(contract.address_hash),
"CompilerVersion" => contract.compiler_version,
"ContractName" => contract.name,
"OptimizationUsed" => if(contract.optimization, do: "1", else: "0")
}
]
params: params,
conn: conn
} do
[contract_1, contract_2, contract_3] = prepare_contracts()
filter_params =
params
|> Map.put("filter", "verified")
|> Map.put("verified_at_start_timestamp", "1663749418")
response =
conn
|> get("/api", filter_params)
|> json_response(200)
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [result(contract_2), result(contract_3)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
test "filtering for only verified contracts with end created_at timestamp < given timestamp shows only verified contracts in that range",
%{
params: params,
conn: conn
} do
[contract_1, contract_2, contract_3] = prepare_contracts()
filter_params =
params
|> Map.put("filter", "verified")
|> Map.put("verified_at_end_timestamp", "1663922218")
response =
conn
|> get("/api", filter_params)
|> json_response(200)
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [result(contract_1), result(contract_2)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -166,12 +270,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(decompiled_smart_contract.address_hash)
}
]
assert response["result"] == [result_not_verified(decompiled_smart_contract.address_hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -188,12 +287,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(smart_contract.address_hash)
}
]
assert response["result"] == [result_not_verified(smart_contract.address_hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -212,10 +306,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert %{
"ABI" => "Contract source code not verified",
"Address" => to_string(smart_contract.address_hash)
} in response["result"]
assert result_not_verified(smart_contract.address_hash) in response["result"]
refute to_string(non_match.address_hash) in Enum.map(response["result"], &Map.get(&1, "Address"))
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
@ -234,12 +325,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(contract_address.hash)
}
]
assert response["result"] == [result_not_verified(contract_address.hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end
@ -261,12 +347,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
assert response["message"] == "OK"
assert response["status"] == "1"
assert response["result"] == [
%{
"ABI" => "Contract source code not verified",
"Address" => to_string(contract_address.hash)
}
]
assert response["result"] == [result_not_verified(contract_address.hash)]
assert :ok = ExJsonSchema.Validator.validate(listcontracts_schema(), response)
end

@ -7,7 +7,8 @@ defmodule Explorer.Etherscan.Contracts do
import Ecto.Query,
only: [
from: 2
from: 2,
where: 3
]
alias Explorer.{Chain, Repo}
@ -80,7 +81,7 @@ defmodule Explorer.Etherscan.Contracts do
def append_proxy_info(address), do: address
def list_verified_contracts(limit, offset) do
def list_verified_contracts(limit, offset, opts) do
query =
from(
smart_contract in SmartContract,
@ -90,7 +91,29 @@ defmodule Explorer.Etherscan.Contracts do
preload: [:address]
)
verified_at_start_timestamp_exist? = Map.has_key?(opts, :verified_at_start_timestamp)
verified_at_end_timestamp_exist? = Map.has_key?(opts, :verified_at_end_timestamp)
query_in_timestamp_range =
cond do
verified_at_start_timestamp_exist? && verified_at_end_timestamp_exist? ->
query
|> where([smart_contract], smart_contract.inserted_at >= ^opts.verified_at_start_timestamp)
|> where([smart_contract], smart_contract.inserted_at < ^opts.verified_at_end_timestamp)
verified_at_start_timestamp_exist? ->
query
|> where([smart_contract], smart_contract.inserted_at >= ^opts.verified_at_start_timestamp)
verified_at_end_timestamp_exist? ->
query
|> where([smart_contract], smart_contract.inserted_at < ^opts.verified_at_end_timestamp)
true ->
query
end
query_in_timestamp_range
|> Repo.replica().all()
|> Enum.map(fn smart_contract ->
Map.put(smart_contract.address, :smart_contract, smart_contract)

Loading…
Cancel
Save