diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a83d3e09..1c18c34df3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,20 @@ ### Features -[#2294](https://github.com/poanetwork/blockscout/pull/2294) - add healthy block period checking endpoint +- [#2294](https://github.com/poanetwork/blockscout/pull/2294) - add healthy block period checking endpoint ### Fixes +- [#2310](https://github.com/poanetwork/blockscout/pull/2310) - parse url for api docs +- [#2299](https://github.com/poanetwork/blockscout/pull/2299) - fix interpolation in error message +- [#2303](https://github.com/poanetwork/blockscout/pull/2303) - fix transaction csv download link - [#2304](https://github.com/poanetwork/blockscout/pull/2304) - footer grid fix for md resolution - [#2291](https://github.com/poanetwork/blockscout/pull/2291) - dashboard fix for md resolution, transactions load fix, block info row fix, addresses page issue, check mark issue ### Chore - [#2305](https://github.com/poanetwork/blockscout/pull/2305) - Improve Address controllers +- [#2302](https://github.com/poanetwork/blockscout/pull/2302) - fix names for xDai source - [#2289](https://github.com/poanetwork/blockscout/pull/2289) - Optional websockets for dev environment +- [#2307](https://github.com/poanetwork/blockscout/pull/2307) - add GoJoy to README ## 2.0.1-beta diff --git a/README.md b/README.md index 5dc91fb8ef..3c95a5d125 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Currently available full-featured block explorers (Etherscan, Etherchain, Blockc | | | [Kotti Testnet](https://kottiexplorer.ethernode.io/) | | | | [Loom](http://plasma-blockexplorer.dappchains.com/) | | | | [Tenda](https://tenda.network) | +| | | [GoJoy Chain](https://gojoychain.com/) | Current BlockScout versions for hosted projects are available [on the forum](https://forum.poa.network/t/deployed-instances-on-blockscout-com/1938). diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex index 5abd8285c6..c3a4c94129 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex @@ -66,10 +66,10 @@
- +
- Download to_string(@address.hash)}) %>><%= gettext("CSV") %> + Download to_string(@address.hash)}) %>><%= gettext("CSV") %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/api_docs_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api_docs_view.ex index f9c280925a..40860e37bb 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api_docs_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api_docs_view.ex @@ -36,7 +36,10 @@ defmodule BlockScoutWeb.APIDocsView do def blockscout_url do if System.get_env("BLOCKSCOUT_HOST") do - "http://" <> System.get_env("BLOCKSCOUT_HOST") + %URI{host: host, scheme: scheme} = URI.parse(Endpoint.url()) + path = System.get_env("NETWORK_PATH") || "/" + + scheme <> "://" <> host <> path else Endpoint.url() end diff --git a/apps/block_scout_web/test/block_scout_web/views/api_docs_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/api_docs_view_test.exs new file mode 100644 index 0000000000..8501f27abc --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/views/api_docs_view_test.exs @@ -0,0 +1,25 @@ +defmodule BlockScoutWeb.ApiDocsViewTest do + use BlockScoutWeb.ConnCase, async: true + + alias BlockScoutWeb.{APIDocsView, Endpoint} + + describe "blockscout_url/0" do + test "returns url with scheme and host without port" do + System.put_env("BLOCKSCOUT_HOST", "localhost") + System.put_env("NETWORK_PATH", "") + + assert APIDocsView.blockscout_url() == "http://localhost" + assert Endpoint.url() == "http://localhost:4002" + end + + test "returns url with scheme and host with path" do + System.put_env("BLOCKSCOUT_HOST", "localhost/chain/dog") + System.put_env("NETWORK_PATH", "/chain/dog") + + assert APIDocsView.blockscout_url() == "http://localhost/chain/dog" + assert Endpoint.url() == "http://localhost:4002" + + System.put_env("NETWORK_PATH", "") + end + end +end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex index 5c39243110..6d9f946554 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex @@ -141,7 +141,9 @@ defmodule EthereumJSONRPC.HTTP do case unstandardized do %{"result" => _, "error" => _} -> raise ArgumentError, - "result and error keys are mutually exclusive in JSONRPC 2.0 response objects, but got #{unstandardized}" + "result and error keys are mutually exclusive in JSONRPC 2.0 response objects, but got #{ + inspect(unstandardized) + }" %{"result" => result} -> Map.put(standardized, :result, result) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index c63fe3e24c..10012bbc67 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -85,8 +85,8 @@ case System.get_env("SUPPLY_MODULE") do :ok end -if System.get_env("SOURCE_MODULE") == "TransactionAndLog" do - config :explorer, Explorer.ExchangeRates.Source, source: Explorer.ExchangeRates.Source.TransactionAndLog +if System.get_env("SOURCE_MODULE") == "TokenBridge" do + config :explorer, Explorer.ExchangeRates.Source, source: Explorer.ExchangeRates.Source.TokenBridge end config :explorer, diff --git a/apps/explorer/lib/explorer/chain/supply/transaction_and_log.ex b/apps/explorer/lib/explorer/chain/supply/transaction_and_log.ex deleted file mode 100644 index 36432094fa..0000000000 --- a/apps/explorer/lib/explorer/chain/supply/transaction_and_log.ex +++ /dev/null @@ -1,78 +0,0 @@ -defmodule Explorer.Chain.Supply.TransactionAndLog do - @moduledoc """ - Defines the supply API for calculating the supply for smaller chains with - specific mint and burn events - """ - use Explorer.Chain.Supply - - alias Explorer.Chain.{InternalTransaction, Log, Wei} - alias Explorer.{Chain, Repo} - - {:ok, base_wei} = Wei.cast(0) - @base_wei base_wei - - {:ok, burn_address} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") - - @burn_address burn_address - @bridge_edge "0x3c798bbcf33115b42c728b8504cff11dd58736e9fa789f1cda2738db7d696b2a" - - import Ecto.Query, only: [from: 2] - - def circulating, do: total(Timex.now()) - - def total, do: total(Timex.now()) - - @doc false - @spec total(DateTime.t()) :: %Decimal{sign: 1} - def total(on_date) do - on_date - |> minted_value - |> Wei.sub(burned_value(on_date)) - |> Wei.to(:ether) - end - - def supply_for_days(days_count) when is_integer(days_count) and days_count > 0 do - past_days = -(days_count - 1) - - result = - for i <- past_days..0, into: %{} do - datetime = Timex.shift(Timex.now(), days: i) - {DateTime.to_date(datetime), total(datetime)} - end - - {:ok, result} - end - - defp minted_value(on_date) do - query = - from( - l in Log, - join: t in assoc(l, :transaction), - join: b in assoc(t, :block), - where: b.timestamp <= ^on_date and l.first_topic == @bridge_edge, - select: fragment("concat('0x', encode(?, 'hex'))", l.data) - ) - - query - |> Repo.all() - |> Enum.reduce(@base_wei, fn data, acc -> - {:ok, wei_value} = Wei.cast(data) - Wei.sum(wei_value, acc) - end) - end - - defp burned_value(on_date) do - query = - from( - it in InternalTransaction, - join: t in assoc(it, :transaction), - join: b in assoc(t, :block), - where: b.timestamp <= ^on_date and it.to_address_hash == ^@burn_address, - select: it.value - ) - - query - |> Repo.all() - |> Enum.reduce(@base_wei, fn data, acc -> Wei.sum(data, acc) end) - end -end diff --git a/apps/explorer/lib/explorer/exchange_rates/source/transaction_and_log.ex b/apps/explorer/lib/explorer/exchange_rates/source/token_bridge.ex similarity index 90% rename from apps/explorer/lib/explorer/exchange_rates/source/transaction_and_log.ex rename to apps/explorer/lib/explorer/exchange_rates/source/token_bridge.ex index 2b8699accc..03234ff649 100644 --- a/apps/explorer/lib/explorer/exchange_rates/source/transaction_and_log.ex +++ b/apps/explorer/lib/explorer/exchange_rates/source/token_bridge.ex @@ -1,6 +1,6 @@ -defmodule Explorer.ExchangeRates.Source.TransactionAndLog do +defmodule Explorer.ExchangeRates.Source.TokenBridge do @moduledoc """ - Adapter for calculating the market cap and total supply from logs and transactions + Adapter for calculating the market cap and total supply from token bridge while still getting other info like price in dollars and bitcoin from a secondary source """ diff --git a/apps/explorer/test/explorer/chain/supply/transaction_and_log_test.exs b/apps/explorer/test/explorer/chain/supply/transaction_and_log_test.exs deleted file mode 100644 index 5126d7acaf..0000000000 --- a/apps/explorer/test/explorer/chain/supply/transaction_and_log_test.exs +++ /dev/null @@ -1,122 +0,0 @@ -defmodule Explorer.Chain.Supply.TransactionAndLogTest do - use Explorer.DataCase - alias Explorer.Chain - alias Explorer.Chain.Supply.TransactionAndLog - - setup do - {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000") - - burn_address = - case Chain.hash_to_address(burn_address_hash) do - {:ok, burn_address} -> burn_address - {:error, :not_found} -> insert(:address, hash: "0x0000000000000000000000000000000000000000") - end - - {:ok, %{burn_address: burn_address}} - end - - describe "total/1" do - test "today with no mints or burns brings zero" do - assert TransactionAndLog.total(Timex.now()) == Decimal.new(0) - end - - test "today with mints and burns calculates a value", %{burn_address: burn_address} do - old_block = insert(:block, timestamp: Timex.shift(Timex.now(), days: -1), number: 1000) - - insert(:log, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 2), - first_topic: "0x3c798bbcf33115b42c728b8504cff11dd58736e9fa789f1cda2738db7d696b2a", - data: "0x0000000000000000000000000000000000000000000000008ac7230489e80000" - ) - - insert(:internal_transaction, - index: 527, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 3), - to_address: burn_address, - value: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - ) - - assert TransactionAndLog.total(Timex.now()) == Decimal.new(9) - end - - test "yesterday with mints and burns calculates a value ignoring whatever happened today", %{ - burn_address: burn_address - } do - old_block = insert(:block, timestamp: Timex.shift(Timex.now(), days: -1), number: 1000) - - insert(:log, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 2), - first_topic: "0x3c798bbcf33115b42c728b8504cff11dd58736e9fa789f1cda2738db7d696b2a", - data: "0x0000000000000000000000000000000000000000000000008ac7230489e80000" - ) - - new_block = insert(:block, timestamp: Timex.now(), number: 1001) - - insert(:internal_transaction, - index: 527, - transaction: - insert(:transaction, block: new_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 3), - to_address: burn_address, - value: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - ) - - assert TransactionAndLog.total(Timex.shift(Timex.now(), days: -1)) == Decimal.new(10) - end - end - - describe "total/0" do - test "calculates the same value as total/1 receiving today's date", %{burn_address: burn_address} do - old_block = insert(:block, timestamp: Timex.shift(Timex.now(), days: -1), number: 1000) - - insert(:log, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 2), - first_topic: "0x3c798bbcf33115b42c728b8504cff11dd58736e9fa789f1cda2738db7d696b2a", - data: "0x0000000000000000000000000000000000000000000000008ac7230489e80000" - ) - - insert(:internal_transaction, - index: 527, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 3), - to_address: burn_address, - value: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - ) - - assert TransactionAndLog.total() == TransactionAndLog.total(Timex.now()) - end - end - - describe "supply_for_days/1" do - test "bring the supply of today and yesterday when receiving 2", %{burn_address: burn_address} do - old_block = insert(:block, timestamp: Timex.shift(Timex.now(), days: -1), number: 1000) - - insert(:log, - transaction: - insert(:transaction, block: old_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 2), - first_topic: "0x3c798bbcf33115b42c728b8504cff11dd58736e9fa789f1cda2738db7d696b2a", - data: "0x0000000000000000000000000000000000000000000000008ac7230489e80000" - ) - - new_block = insert(:block, timestamp: Timex.now(), number: 1001) - - insert(:internal_transaction, - index: 527, - transaction: - insert(:transaction, block: new_block, block_number: 1000, cumulative_gas_used: 1, gas_used: 1, index: 3), - to_address: burn_address, - value: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - ) - - expected_result = %{ - Timex.shift(Timex.today(), days: -1) => Decimal.new(10), - Timex.today() => Decimal.new(9) - } - - assert TransactionAndLog.supply_for_days(2) == {:ok, expected_result} - end - end -end diff --git a/apps/explorer/test/explorer/exchange_rates/source/transaction_and_log_test.exs b/apps/explorer/test/explorer/exchange_rates/source/token_bridge_test.exs similarity index 78% rename from apps/explorer/test/explorer/exchange_rates/source/transaction_and_log_test.exs rename to apps/explorer/test/explorer/exchange_rates/source/token_bridge_test.exs index 47aa09f805..d5bd5f9b96 100644 --- a/apps/explorer/test/explorer/exchange_rates/source/transaction_and_log_test.exs +++ b/apps/explorer/test/explorer/exchange_rates/source/token_bridge_test.exs @@ -1,6 +1,6 @@ -defmodule Explorer.ExchangeRates.Source.TransactionAndLogTest do +defmodule Explorer.ExchangeRates.Source.TokenBridgeTest do use Explorer.DataCase - alias Explorer.ExchangeRates.Source.TransactionAndLog + alias Explorer.ExchangeRates.Source.TokenBridge alias Explorer.ExchangeRates.Token @json """ @@ -27,7 +27,7 @@ defmodule Explorer.ExchangeRates.Source.TransactionAndLogTest do describe "format_data/1" do test "bring a list with one %Token{}" do - assert [%Token{}] = TransactionAndLog.format_data(@json) + assert [%Token{}] = TokenBridge.format_data(@json) end end end diff --git a/docs/env-variables.md b/docs/env-variables.md index 4cbef49e82..0c93460150 100644 --- a/docs/env-variables.md +++ b/docs/env-variables.md @@ -21,7 +21,7 @@ Below is a table outlining the environment variables utilized by BlockScout. | `METADATA_CONTRACT` | | This environment variable is specifically used by POA Network to obtain Validators information to display in the UI. | (empty) | all | | `VALIDATORS_CONTRACT` | | This environment variable is specifically used by POA Network to obtain the Emission Fund contract. | (empty) | all | | `SUPPLY_MODULE` | | This environment variable is used by the xDai Chain in order to tell the application how to calculate the total supply of the chain. | false | all | -| `SOURCE_MODULE` | | This environment variable is used to calculate the total supply and is specifically used by the xDai Chain. | false | all | +| `SOURCE_MODULE` | | This environment variable is used to calculate the exchange rate and is specifically used by the xDai Chain. | false | all | | `DATABASE_URL` | | Production environment variable to define the Database endpoint. | (empty) | all | | `POOL_SIZE` | | Production environment variable to define the number of database connections allowed. | 20 | all | | `ECTO_USE_SSL`| | Production environment variable to use SSL on Ecto queries. | true | all | @@ -33,7 +33,7 @@ Below is a table outlining the environment variables utilized by BlockScout. | `HEART_COMMAND` | | Production environment variable to restart the application in the event of a crash. | systemctl restart explorer.service | all | | `BLOCKSCOUT_VERSION` | | Added to the footer to signify the current BlockScout version. | (empty) | v1.3.4+ | | `RELEASE_LINK` | | The link to Blockscout release notes in the footer. | https://github.com/poanetwork/
blockscout/releases/
tag/${BLOCKSCOUT_VERSION} | v1.3.5+ | -| `ELIXIR_VERSION` | | Elixir version to install on the node before Blockscout deploy. | (empty) | all | +| `ELIXIR_VERSION` | | Elixir version to install on the node before Blockscout deploy. | (empty) | all | | `BLOCK_TRANSFORMER` | | Transformer for blocks: base or clique. | base | v1.3.4+ | | `GRAPHIQL _TRANSACTION` | | Default transaction in query to GraphiQL. | (empty) | v1.3.4+ | | `FIRST_BLOCK` | | The block number, where indexing begins from. | 0 | v1.3.8+ |