Skip to content

Commit 7aab809

Browse files
JOYclaude
andcommitted
chore: merge upstream v11.0.2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 parents 4c6fba8 + ea6945a commit 7aab809

33 files changed

Lines changed: 826 additions & 107 deletions

File tree

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# Changelog
22

3+
## 11.0.2
4+
5+
### 🐛 Bug Fixes
6+
7+
- Process empty list of changes on fetching contract codes ((#14312)[https://github.com/blockscout/blockscout/pull/14312])
8+
- Add fallback for empty "to" in Geth selfdestruct ([#14256](https://github.com/blockscout/blockscout/issues/14256))
9+
- Trim contractaddresses in getcontractcreation ([#14306](https://github.com/blockscout/blockscout/issues/14306))
10+
- Adapt maybe_reject_zero_value for empty blocks ([#14309](https://github.com/blockscout/blockscout/issues/14309))
11+
- Add missing internal transactions address preload ([#14308](https://github.com/blockscout/blockscout/issues/14308))
12+
- Fix some web tests ([#14310][https://github.com/blockscout/blockscout/pull/14310])
13+
14+
### ⚙️ Miscellaneous Tasks
15+
16+
- Disable on-demand IT fetcher test for rsk and filecoin ([#14314](https://github.com/blockscout/blockscout/pull/14314))
17+
- Disable flaky contract code compiler doctest ([#14313](https://github.com/blockscout/blockscout/pull/14313))
18+
- Add coverage for core API v2 views ([#14254](https://github.com/blockscout/blockscout/issues/14254))
19+
20+
321
## 11.0.1
422

523
### 🐛 Bug Fixes

apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
4545
def getcontractcreation(conn, %{"contractaddresses" => contract_address_hash_strings} = params) do
4646
addresses =
4747
contract_address_hash_strings
48-
|> String.split(",")
48+
|> String.split(",", trim: true)
49+
|> Enum.map(&String.trim/1)
50+
|> Enum.reject(&(&1 == ""))
4951
|> Enum.take(@addresses_limit)
5052
|> Enum.map(fn address_hash_string ->
5153
case validate_address(address_hash_string, params) do

apps/block_scout_web/lib/block_scout_web/schemas/api/v2/celo/election_reward.ex

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ defmodule BlockScoutWeb.Schemas.API.V2.Celo.ElectionReward do
2323
required: [
2424
:amount,
2525
:account,
26-
:associated_account,
27-
:epoch_number
26+
:associated_account
2827
],
2928
additionalProperties: false
3029
})

apps/block_scout_web/mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ defmodule BlockScoutWeb.Mixfile do
1919
lockfile: "../../mix.lock",
2020
package: package(),
2121
start_permanent: Mix.env() == :prod,
22-
version: "11.0.1",
22+
version: "11.0.2",
2323
xref: [
2424
exclude: [
2525
Explorer.Chain.Beacon.Reader,

apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs

Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,78 +2499,82 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
24992499
assert :ok = ExJsonSchema.Validator.validate(txlistinternal_schema(), response)
25002500
end
25012501

2502-
test "via on-demand fetcher", %{conn: conn} do
2503-
original_config = Application.get_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions)
2502+
if Application.compile_env(:explorer, :chain_type) not in [:rsk, :filecoin] do
2503+
test "via on-demand fetcher", %{conn: conn} do
2504+
original_config = Application.get_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions)
25042505

2505-
Application.put_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions,
2506-
enabled: true,
2507-
storage_period: 0
2508-
)
2506+
Application.put_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions,
2507+
enabled: true,
2508+
storage_period: 0
2509+
)
25092510

2510-
transaction = :transaction |> insert() |> with_block()
2511-
2512-
expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn
2513-
[%{id: id, params: _}], _ ->
2514-
{:ok,
2515-
[
2516-
%{
2517-
id: id,
2518-
result: %{
2519-
"type" => "create",
2520-
"from" => "0x117b358218da5a4f647072ddb50ded038ed63d17",
2521-
"to" => "0x205a6b72ce16736c9d87172568a9c0cb9304de0d",
2522-
"value" => "0x0",
2523-
"gas" => "0x106f5",
2524-
"gasUsed" => "0x106f5",
2525-
"input" =>
2526-
"0x608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea26469706673582212209a159a4f3847890f10bfb87871a61eba91c5dbf5ee3cf6398207e292eee22a1664736f6c63430008070033",
2527-
"output" =>
2528-
"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea26469706673582212209a159a4f3847890f10bfb87871a61eba91c5dbf5ee3cf6398207e292eee22a1664736f6c63430008070033"
2529-
}
2530-
}
2531-
]}
2532-
end)
2511+
on_exit(fn ->
2512+
Application.put_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions, original_config)
2513+
end)
25332514

2534-
Application.put_env(:ethereum_jsonrpc, EthereumJSONRPC.Geth, tracer: "call_tracer", debug_trace_timeout: "5s")
2515+
transaction = :transaction |> insert() |> with_block()
25352516

2536-
expected_result = [
2537-
%{
2538-
"blockNumber" => "#{transaction.block_number}",
2539-
"callType" => "",
2540-
"contractAddress" => "0x205a6b72ce16736c9d87172568a9c0cb9304de0d",
2541-
"errCode" => "",
2542-
"from" => "0x117b358218da5a4f647072ddb50ded038ed63d17",
2543-
"gas" => "67317",
2544-
"gasUsed" => "67317",
2545-
"index" => "0",
2546-
"input" => "",
2547-
"isError" => "0",
2548-
"timeStamp" => "#{DateTime.to_unix(transaction.block.timestamp)}",
2549-
"to" => "",
2550-
"transactionHash" => "#{transaction.hash}",
2551-
"type" => "create",
2552-
"value" => "0"
2553-
}
2554-
]
2555-
2556-
params = %{
2557-
"module" => "account",
2558-
"action" => "txlistinternal",
2559-
"txhash" => "#{transaction.hash}",
2560-
"include_zero_value" => "true"
2561-
}
2517+
expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn
2518+
[%{id: id, params: _}], _ ->
2519+
{:ok,
2520+
[
2521+
%{
2522+
id: id,
2523+
result: %{
2524+
"type" => "create",
2525+
"from" => "0x117b358218da5a4f647072ddb50ded038ed63d17",
2526+
"to" => "0x205a6b72ce16736c9d87172568a9c0cb9304de0d",
2527+
"value" => "0x0",
2528+
"gas" => "0x106f5",
2529+
"gasUsed" => "0x106f5",
2530+
"input" =>
2531+
"0x608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea26469706673582212209a159a4f3847890f10bfb87871a61eba91c5dbf5ee3cf6398207e292eee22a1664736f6c63430008070033",
2532+
"output" =>
2533+
"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea26469706673582212209a159a4f3847890f10bfb87871a61eba91c5dbf5ee3cf6398207e292eee22a1664736f6c63430008070033"
2534+
}
2535+
}
2536+
]}
2537+
end)
25622538

2563-
assert response =
2564-
conn
2565-
|> get("/api/v1", params)
2566-
|> json_response(200)
2539+
Application.put_env(:ethereum_jsonrpc, EthereumJSONRPC.Geth, tracer: "call_tracer", debug_trace_timeout: "5s")
2540+
2541+
expected_result = [
2542+
%{
2543+
"blockNumber" => "#{transaction.block_number}",
2544+
"callType" => "",
2545+
"contractAddress" => "0x205a6b72ce16736c9d87172568a9c0cb9304de0d",
2546+
"errCode" => "",
2547+
"from" => "0x117b358218da5a4f647072ddb50ded038ed63d17",
2548+
"gas" => "67317",
2549+
"gasUsed" => "67317",
2550+
"index" => "0",
2551+
"input" => "",
2552+
"isError" => "0",
2553+
"timeStamp" => "#{DateTime.to_unix(transaction.block.timestamp)}",
2554+
"to" => "",
2555+
"transactionHash" => "#{transaction.hash}",
2556+
"type" => "create",
2557+
"value" => "0"
2558+
}
2559+
]
2560+
2561+
params = %{
2562+
"module" => "account",
2563+
"action" => "txlistinternal",
2564+
"txhash" => "#{transaction.hash}",
2565+
"include_zero_value" => "true"
2566+
}
25672567

2568-
assert response["result"] == expected_result
2569-
assert response["status"] == "1"
2570-
assert response["message"] == "OK"
2571-
assert :ok = ExJsonSchema.Validator.validate(txlistinternal_schema(), response)
2568+
assert response =
2569+
conn
2570+
|> get("/api/v1", params)
2571+
|> json_response(200)
25722572

2573-
Application.put_env(:explorer, Explorer.Migrator.DeleteZeroValueInternalTransactions, original_config)
2573+
assert response["result"] == expected_result
2574+
assert response["status"] == "1"
2575+
assert response["message"] == "OK"
2576+
assert :ok = ExJsonSchema.Validator.validate(txlistinternal_schema(), response)
2577+
end
25742578
end
25752579
end
25762580

apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,49 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
11031103
assert creation_bytecode == to_string(transaction.input)
11041104
end
11051105

1106+
test "returns contract creation info for addresses separated by comma and whitespace", %{conn: conn, params: params} do
1107+
{:ok, block_timestamp, _} = DateTime.from_iso8601("2021-05-05T21:42:11.000000Z")
1108+
1109+
address = insert(:contract_address)
1110+
address_1 = insert(:contract_address)
1111+
1112+
transaction =
1113+
insert(:transaction,
1114+
created_contract_address: address,
1115+
block_timestamp: block_timestamp
1116+
)
1117+
1118+
transaction_1 =
1119+
insert(:transaction,
1120+
created_contract_address: address_1,
1121+
block_timestamp: block_timestamp
1122+
)
1123+
1124+
%{
1125+
"status" => "1",
1126+
"message" => "OK",
1127+
"result" => result
1128+
} =
1129+
conn
1130+
|> get(
1131+
"/api",
1132+
Map.put(params, "contractaddresses", "#{to_string(address)}, #{to_string(address_1)}")
1133+
)
1134+
|> json_response(200)
1135+
1136+
assert length(result) == 2
1137+
1138+
assert Enum.map(result, & &1["contractAddress"]) == [
1139+
to_string(address.hash),
1140+
to_string(address_1.hash)
1141+
]
1142+
1143+
assert Enum.map(result, & &1["txHash"]) == [
1144+
to_string(transaction.hash),
1145+
to_string(transaction_1.hash)
1146+
]
1147+
end
1148+
11061149
test "get contract creation info via internal transaction", %{conn: conn, params: params} do
11071150
{:ok, block_timestamp, _} = DateTime.from_iso8601("2021-05-05T21:42:11.000000Z")
11081151
unix_timestamp = DateTime.to_unix(block_timestamp, :second)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
defmodule BlockScoutWeb.API.V2.AddressViewTest do
2+
use BlockScoutWeb.ConnCase, async: true
3+
4+
alias BlockScoutWeb.API.V2.AddressView
5+
alias Explorer.Chain.Wei
6+
7+
describe "prepare_coin_balance_history_entry/1" do
8+
test "returns map with expected keys and values" do
9+
block_timestamp = ~U[2023-01-01 00:00:00Z]
10+
delta = Decimal.new(100)
11+
value = Decimal.new(200)
12+
13+
coin_balance = %{
14+
transaction_hash: nil,
15+
block_number: 10,
16+
delta: delta,
17+
value: value,
18+
block_timestamp: block_timestamp
19+
}
20+
21+
result = AddressView.prepare_coin_balance_history_entry(coin_balance)
22+
23+
assert result["transaction_hash"] == nil
24+
assert result["block_number"] == 10
25+
assert Decimal.equal?(result["delta"], delta)
26+
assert Decimal.equal?(result["value"], value)
27+
assert result["block_timestamp"] == block_timestamp
28+
end
29+
end
30+
31+
describe "prepare_coin_balance_history_by_day_entry/1" do
32+
test "returns date and value" do
33+
value = Decimal.new(500)
34+
coin_balance_by_day = %{date: ~D[2023-01-01], value: value}
35+
36+
result = AddressView.prepare_coin_balance_history_by_day_entry(coin_balance_by_day)
37+
38+
assert result["date"] == ~D[2023-01-01]
39+
assert Decimal.equal?(result["value"], value)
40+
end
41+
end
42+
43+
describe "prepare_address_for_list/1" do
44+
test "includes coin balance and transaction count" do
45+
address =
46+
build(:address,
47+
fetched_coin_balance: %Wei{value: Decimal.new(100)},
48+
transactions_count: 5
49+
)
50+
51+
result = AddressView.prepare_address_for_list(address)
52+
53+
assert Decimal.equal?(result[:coin_balance], Decimal.new(100))
54+
assert result[:transactions_count] == "5"
55+
assert Map.has_key?(result, "hash")
56+
end
57+
58+
test "sets coin balance to nil when fetched coin balance is missing" do
59+
address = build(:address, fetched_coin_balance: nil, transactions_count: 3)
60+
61+
result = AddressView.prepare_address_for_list(address)
62+
63+
assert result[:coin_balance] == nil
64+
assert result[:transactions_count] == "3"
65+
end
66+
end
67+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
defmodule BlockScoutWeb.API.V2.ApiViewTest do
2+
use BlockScoutWeb.ConnCase, async: true
3+
4+
alias BlockScoutWeb.API.V2.ApiView
5+
6+
describe "render/2" do
7+
test "renders message.json" do
8+
assert %{"message" => "ok"} = ApiView.render("message.json", %{message: "ok"})
9+
end
10+
11+
test "renders smart_contract_audit_report_changeset_errors.json" do
12+
changeset =
13+
{%{}, %{audit_report_url: :string}}
14+
|> Ecto.Changeset.cast(%{}, [])
15+
|> Ecto.Changeset.add_error(:audit_report_url, "can't be blank")
16+
17+
result =
18+
ApiView.render("smart_contract_audit_report_changeset_errors.json", %{changeset: changeset})
19+
20+
assert result["message"] == "Error on inserting audit report"
21+
assert is_map(result["errors"])
22+
assert map_size(result["errors"]) > 0
23+
end
24+
end
25+
end

0 commit comments

Comments
 (0)