diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 8eb84c5df6..c87ed7e041 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -4,6 +4,7 @@ on: push: branches: - account + - np-separate-account-separate-db env: MIX_ENV: test @@ -37,7 +38,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps- @@ -97,7 +98,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -121,7 +122,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -144,7 +145,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_13-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -184,7 +185,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -210,7 +211,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -238,7 +239,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -284,7 +285,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -343,7 +344,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -399,7 +400,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -466,7 +467,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -527,7 +528,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_12-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_14-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" diff --git a/.gitignore b/.gitignore index a069fb5fd6..2f86dc1f3f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ /*.ez /logs +# mix dialyzer artifacts +/priv/plts + # Generated on crash by the VM erl_crash.dump diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index 2787d53282..f6e44d7013 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -8,7 +8,7 @@ import Config # General application configuration config :block_scout_web, namespace: BlockScoutWeb, - ecto_repos: [Explorer.Repo] + ecto_repos: [Explorer.Repo, Explorer.Repo.Account] config :block_scout_web, admin_panel_enabled: System.get_env("ADMIN_PANEL_ENABLED", "") == "true" @@ -97,7 +97,7 @@ config :hammer, config :block_scout_web, BlockScoutWeb.Guardian, issuer: "block_scout_web" config :guardian, Guardian.DB, - repo: Explorer.Repo, + repo: Explorer.Repo.Account, schema_name: "guardian_tokens", sweep_interval: 60 diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex index 9f11f75e6d..529de91d5b 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/tags_controller.ex @@ -17,7 +17,8 @@ defmodule BlockScoutWeb.Account.Api.V1.TagsController do uid = Plug.current_claims(conn)["sub"] with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, {:address_hash, {:ok, address_hash}} <- {:address_hash, Address.cast(address_hash)} do GetAddressTags.get_address_tags(address_hash, %{id: identity.id, watchlist_id: watchlist.id}) else @@ -57,7 +58,8 @@ defmodule BlockScoutWeb.Account.Api.V1.TagsController do uid = Plug.current_claims(conn)["sub"] with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, false <- is_nil(transaction) do GetTransactionTags.get_transaction_with_addresses_tags(transaction, %{ id: identity.id, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex index 63e14cb789..6b3e9098ea 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v1/user_controller.ex @@ -30,11 +30,9 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do uid = Plug.current_claims(conn)["sub"] with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, - watchlist_with_addresses <- - Repo.preload(watchlist, - watchlist_addresses: {from(wa in WatchlistAddress, order_by: [desc: wa.id]), [:address]} - ) do + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, + watchlist_with_addresses <- preload_watchlist_address_fetched_coin_balance(watchlist) do conn |> put_status(200) |> render(:watchlist_addresses, %{ @@ -48,7 +46,8 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do uid = Plug.current_claims(conn)["sub"] with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, {count, _} <- WatchlistAddress.delete(watchlist_address_id, watchlist.id), {:watchlist_delete, true} <- {:watchlist_delete, count > 0} do conn @@ -100,10 +99,11 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do } with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, {:ok, watchlist_address} <- WatchlistAddress.create(Map.put(watchlist_params, :watchlist_id, watchlist.id)), - watchlist_address_preloaded <- Repo.preload(watchlist_address, :address) do + watchlist_address_preloaded <- WatchlistAddress.preload_address_fetched_coin_balance(watchlist_address) do conn |> put_status(200) |> render(:watchlist_address, %{ @@ -158,10 +158,11 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do } with {:identity, [%Identity{} = identity]} <- {:identity, UserFromAuth.find_identity(uid)}, - {:watchlist, %{watchlists: [watchlist | _]}} <- {:watchlist, Repo.preload(identity, :watchlists)}, + {:watchlist, %{watchlists: [watchlist | _]}} <- + {:watchlist, Repo.account_repo().preload(identity, :watchlists)}, {:ok, watchlist_address} <- WatchlistAddress.update(Map.put(watchlist_params, :watchlist_id, watchlist.id)), - watchlist_address_preloaded <- Repo.preload(watchlist_address, :address) do + watchlist_address_preloaded <- WatchlistAddress.preload_address_fetched_coin_balance(watchlist_address) do conn |> put_status(200) |> render(:watchlist_address, %{ @@ -482,4 +483,10 @@ defmodule BlockScoutWeb.Account.Api.V1.UserController do defp reject_nil_map_values(map) when is_map(map) do Map.reject(map, fn {_k, v} -> is_nil(v) end) end + + defp preload_watchlist_address_fetched_coin_balance(watchlist) do + watchlist + |> Repo.account_repo().preload(watchlist_addresses: from(wa in WatchlistAddress, order_by: [desc: wa.id])) + |> WatchlistAddress.preload_address_fetched_coin_balance() + end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/watchlist_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/watchlist_controller.ex index b774d57c44..f8c548322f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/account/watchlist_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/watchlist_controller.ex @@ -19,7 +19,8 @@ defmodule BlockScoutWeb.Account.WatchlistController do defp watchlist_with_addresses(user) do Watchlist - |> Repo.get(user.watchlist_id) - |> Repo.preload(watchlist_addresses: {from(wa in WatchlistAddress, order_by: [desc: wa.id]), [:address]}) + |> Repo.account_repo().get(user.watchlist_id) + |> Repo.account_repo().preload(watchlist_addresses: from(wa in WatchlistAddress, order_by: [desc: wa.id])) + |> WatchlistAddress.preload_address_fetched_coin_balance() end end diff --git a/apps/block_scout_web/lib/block_scout_web/models/get_address_tags.ex b/apps/block_scout_web/lib/block_scout_web/models/get_address_tags.ex index ea4b5b32da..4a834f3fef 100644 --- a/apps/block_scout_web/lib/block_scout_web/models/get_address_tags.ex +++ b/apps/block_scout_web/lib/block_scout_web/models/get_address_tags.ex @@ -54,7 +54,7 @@ defmodule BlockScoutWeb.Models.GetAddressTags do select: %{label: ta.name, display_name: ta.name, address_hash: ta.address_hash} ) - Repo.all(query) + Repo.account_repo().all(query) end def get_personal_tags(_, _), do: [] @@ -68,7 +68,7 @@ defmodule BlockScoutWeb.Models.GetAddressTags do select: %{label: wa.name, display_name: wa.name} ) - Repo.all(query) + Repo.account_repo().all(query) end def get_watchlist_names_on_address(_, _), do: [] diff --git a/apps/block_scout_web/lib/block_scout_web/models/get_transaction_tags.ex b/apps/block_scout_web/lib/block_scout_web/models/get_transaction_tags.ex index 776622c2b4..bee4eb9354 100644 --- a/apps/block_scout_web/lib/block_scout_web/models/get_transaction_tags.ex +++ b/apps/block_scout_web/lib/block_scout_web/models/get_transaction_tags.ex @@ -21,7 +21,7 @@ defmodule BlockScoutWeb.Models.GetTransactionTags do def get_transaction_with_addresses_tags(_, _), do: %{personal_tags: [], watchlist_names: [], personal_tx_tag: nil} def get_transaction_tags(transaction_hash, %{id: identity_id}) do - Repo.get_by(TagTransaction, tx_hash: transaction_hash, identity_id: identity_id) + Repo.account_repo().get_by(TagTransaction, tx_hash: transaction_hash, identity_id: identity_id) end def get_transaction_tags(_, _), do: nil diff --git a/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex b/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex index fe45d6fbf0..cc1483b929 100644 --- a/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex +++ b/apps/block_scout_web/lib/block_scout_web/models/user_from_auth.ex @@ -37,7 +37,7 @@ defmodule BlockScoutWeb.Models.UserFromAuth do end defp create_identity(auth) do - with {:ok, %Identity{} = identity} <- Repo.insert(new_identity(auth)), + with {:ok, %Identity{} = identity} <- Repo.account_repo().insert(new_identity(auth)), {:ok, _watchlist} <- add_watchlist(identity) do identity end @@ -46,7 +46,7 @@ defmodule BlockScoutWeb.Models.UserFromAuth do defp update_identity(identity, attrs) do identity |> Identity.changeset(attrs) - |> Repo.update() + |> Repo.account_repo().update() end defp new_identity(auth) do @@ -62,12 +62,12 @@ defmodule BlockScoutWeb.Models.UserFromAuth do defp add_watchlist(identity) do watchlist = Ecto.build_assoc(identity, :watchlists, %{}) - with {:ok, _} <- Repo.insert(watchlist), + with {:ok, _} <- Repo.account_repo().insert(watchlist), do: {:ok, identity} end def find_identity(auth_or_uid) do - Repo.all(query_identity(auth_or_uid)) + Repo.account_repo().all(query_identity(auth_or_uid)) end def query_identity(%Auth{} = auth) do @@ -79,7 +79,7 @@ defmodule BlockScoutWeb.Models.UserFromAuth do end defp basic_info(auth, identity) do - %{watchlists: [watchlist | _]} = Repo.preload(identity, :watchlists) + %{watchlists: [watchlist | _]} = Repo.account_repo().preload(identity, :watchlists) %{ id: identity.id, diff --git a/apps/block_scout_web/lib/block_scout_web/templates/account/watchlist_address/row.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/account/watchlist_address/row.html.eex index b8fa97dd5b..467c15952f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/account/watchlist_address/row.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/account/watchlist_address/row.html.eex @@ -8,12 +8,12 @@ - <%= balance_ether(@watchlist_address.address) %> + <%= balance_ether(@watchlist_address.fetched_coin_balance) %>
( watchlist.id, "address_hash" => watchlist.address_hash, "name" => watchlist.name, - "address_balance" => if(watchlist.address.fetched_coin_balance, do: watchlist.address.fetched_coin_balance.value), + "address_balance" => if(watchlist.fetched_coin_balance, do: watchlist.fetched_coin_balance.value), "exchange_rate" => exchange_rate.usd_value, "notification_settings" => %{ "native" => %{ diff --git a/apps/block_scout_web/lib/block_scout_web/views/account/watchlist_address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/account/watchlist_address_view.ex index 0605862572..f3f538399e 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/account/watchlist_address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/account/watchlist_address_view.ex @@ -3,11 +3,9 @@ defmodule BlockScoutWeb.Account.WatchlistAddressView do import BlockScoutWeb.AddressView, only: [trimmed_hash: 1] import BlockScoutWeb.WeiHelpers, only: [format_wei_value: 2] - alias Explorer.Chain.Address + def balance_ether(nil), do: "" - def balance_ether(%Address{fetched_coin_balance: nil}), do: "" - - def balance_ether(%Address{fetched_coin_balance: balance}) do + def balance_ether(balance) do format_wei_value(balance, :ether) end end diff --git a/apps/block_scout_web/test/block_scout_web/models/user_from_auth_test.exs b/apps/block_scout_web/test/block_scout_web/models/user_from_auth_test.exs index d1d99501a3..2d13f11600 100644 --- a/apps/block_scout_web/test/block_scout_web/models/user_from_auth_test.exs +++ b/apps/block_scout_web/test/block_scout_web/models/user_from_auth_test.exs @@ -37,13 +37,13 @@ defmodule UserFromAuthTest do email: "john@blockscout.com", name: "John Snow", uid: "github|666666" - } = Identity |> first |> Repo.one() + } = Identity |> first |> Repo.account_repo().one() %{ id: watchlist_id, identity_id: ^identity_id, name: "default" - } = Watchlist |> first |> Repo.one() + } = Watchlist |> first |> Repo.account_repo().one() assert {:ok, %{ @@ -84,13 +84,13 @@ defmodule UserFromAuthTest do email: "john@blockscout.com", name: "John Snow", uid: "google-oauth2|666666" - } = Identity |> first |> Repo.one() + } = Identity |> first |> Repo.account_repo().one() %{ id: watchlist_id, identity_id: ^identity_id, name: "default" - } = Watchlist |> first |> Repo.one() + } = Watchlist |> first |> Repo.account_repo().one() assert {:ok, %{ diff --git a/apps/block_scout_web/test/support/conn_case.ex b/apps/block_scout_web/test/support/conn_case.ex index 787709ccb7..5ae6216f0c 100644 --- a/apps/block_scout_web/test/support/conn_case.ex +++ b/apps/block_scout_web/test/support/conn_case.ex @@ -37,9 +37,11 @@ defmodule BlockScoutWeb.ConnCase do @dialyzer {:nowarn_function, __ex_unit_setup_0: 1} setup tags do :ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo) + :ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo.Account) unless tags[:async] do Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, {:shared, self()}) + Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo.Account, {:shared, self()}) end Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Transactions.child_id()) diff --git a/apps/block_scout_web/test/test_helper.exs b/apps/block_scout_web/test/test_helper.exs index 9aeb6c8fa7..11c846c47c 100644 --- a/apps/block_scout_web/test/test_helper.exs +++ b/apps/block_scout_web/test/test_helper.exs @@ -25,6 +25,7 @@ ExUnit.start() Mox.defmock(Explorer.ExchangeRates.Source.TestSource, for: Explorer.ExchangeRates.Source) Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, :manual) +Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo.Account, :manual) Absinthe.Test.prime(BlockScoutWeb.Schema) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index cc58587a54..c58d3bfd37 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -7,7 +7,7 @@ import Config # General application configuration config :explorer, - ecto_repos: [Explorer.Repo], + ecto_repos: [Explorer.Repo, Explorer.Repo.Account], token_functions_reader_max_retries: 3 config :explorer, Explorer.Counters.AverageBlockTime, diff --git a/apps/explorer/config/dev.exs b/apps/explorer/config/dev.exs index 7d7bd024a7..1ccfb34b6d 100644 --- a/apps/explorer/config/dev.exs +++ b/apps/explorer/config/dev.exs @@ -6,6 +6,9 @@ config :explorer, Explorer.Repo, timeout: :timer.seconds(80) # Configure API database config :explorer, Explorer.Repo.Replica1, timeout: :timer.seconds(80) +# Configure Account database +config :explorer, Explorer.Repo.Account, timeout: :timer.seconds(80) + config :explorer, Explorer.Tracer, env: "dev", disabled?: true config :logger, :explorer, diff --git a/apps/explorer/config/prod.exs b/apps/explorer/config/prod.exs index 8b42271e33..2d389e59d6 100644 --- a/apps/explorer/config/prod.exs +++ b/apps/explorer/config/prod.exs @@ -10,6 +10,11 @@ config :explorer, Explorer.Repo.Replica1, prepare: :unnamed, timeout: :timer.seconds(60) +# Configures Account database +config :explorer, Explorer.Repo.Account, + prepare: :unnamed, + timeout: :timer.seconds(60) + config :explorer, Explorer.Tracer, env: "production", disabled?: true config :logger, :explorer, diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index 3c7fc40fec..1b3b160791 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -23,6 +23,16 @@ config :explorer, Explorer.Repo.Replica1, timeout: :timer.seconds(60), queue_target: 1000 +# Configure API database +config :explorer, Explorer.Repo.Account, + database: "explorer_test_account", + hostname: "localhost", + pool: Ecto.Adapters.SQL.Sandbox, + # Default of `5_000` was too low for `BlockFetcher` test + ownership_timeout: :timer.minutes(1), + timeout: :timer.seconds(60), + queue_target: 1000 + config :logger, :explorer, level: :warn, path: Path.absname("logs/test/explorer.log") diff --git a/apps/explorer/lib/explorer/account/api/key.ex b/apps/explorer/lib/explorer/account/api/key.ex index ef24979034..ab80d41ec2 100644 --- a/apps/explorer/lib/explorer/account/api/key.ex +++ b/apps/explorer/lib/explorer/account/api/key.ex @@ -41,14 +41,14 @@ defmodule Explorer.Account.Api.Key do def create(attrs) do %__MODULE__{} |> changeset(Map.put(attrs, :value, generate_api_key())) - |> Repo.insert() + |> Repo.account_repo().insert() end def api_key_count_constraint(%Changeset{changes: %{identity_id: identity_id}} = api_key) do if identity_id |> api_keys_by_identity_id_query() |> limit(@max_key_per_account) - |> Repo.aggregate(:count, :value) >= @max_key_per_account do + |> Repo.account_repo().aggregate(:count, :value) >= @max_key_per_account do api_key |> add_error(:name, "Max #{@max_key_per_account} keys per account") else @@ -81,7 +81,7 @@ defmodule Explorer.Account.Api.Key do def get_api_key_by_value_and_identity_id(value, identity_id) when not is_nil(value) and not is_nil(identity_id) do value |> api_key_by_value_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_api_key_by_value_and_identity_id(_, _), do: nil @@ -89,7 +89,7 @@ defmodule Explorer.Account.Api.Key do def update(%{value: api_key_value, identity_id: identity_id} = attrs) do with api_key <- get_api_key_by_value_and_identity_id(api_key_value, identity_id), false <- is_nil(api_key) do - api_key |> changeset(attrs) |> Repo.update() + api_key |> changeset(attrs) |> Repo.account_repo().update() else true -> {:error, %{reason: :item_not_found}} @@ -99,7 +99,7 @@ defmodule Explorer.Account.Api.Key do def delete(api_key_value, identity_id) when not is_nil(api_key_value) and not is_nil(identity_id) do api_key_value |> api_key_by_value_and_identity_id_query(identity_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete(_, _), do: nil @@ -107,7 +107,7 @@ defmodule Explorer.Account.Api.Key do def get_api_keys_by_identity_id(id) when not is_nil(id) do id |> api_keys_by_identity_id_query() - |> Repo.all() + |> Repo.account_repo().all() end def get_api_keys_by_identity_id(_), do: nil @@ -116,8 +116,8 @@ defmodule Explorer.Account.Api.Key do if match?({:ok, _casted_api_key}, UUID.cast(api_key_value)) do __MODULE__ |> where([api_key], api_key.value == ^api_key_value) - |> Repo.one() - |> Repo.preload(identity: :plan) + |> Repo.account_repo().one() + |> Repo.account_repo().preload(identity: :plan) else nil end diff --git a/apps/explorer/lib/explorer/account/custom_abi.ex b/apps/explorer/lib/explorer/account/custom_abi.ex index e18e809ae3..4be56dd007 100644 --- a/apps/explorer/lib/explorer/account/custom_abi.ex +++ b/apps/explorer/lib/explorer/account/custom_abi.ex @@ -8,7 +8,7 @@ defmodule Explorer.Account.CustomABI do alias Ecto.Changeset alias Explorer.Account.Identity alias Explorer.{Chain, Repo} - alias Explorer.Chain.{Address, Hash} + alias Explorer.Chain.Hash import Ecto.Changeset @@ -19,8 +19,9 @@ defmodule Explorer.Account.CustomABI do field(:abi, {:array, :map}) field(:given_abi, :string, virtual: true) field(:abi_validating_error, :string, virtual: true) + field(:address_hash, Hash.Address, null: false) + belongs_to(:identity, Identity) - belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address) timestamps() end @@ -34,7 +35,6 @@ defmodule Explorer.Account.CustomABI do |> validate_custom_abi() |> check_smart_contract_address() |> foreign_key_constraint(:identity_id, message: "User not found") - |> foreign_key_constraint(:address_hash, message: "Address not found") |> unique_constraint([:identity_id, :address_hash], message: "Custom ABI for this address has already been added before" ) @@ -48,23 +48,23 @@ defmodule Explorer.Account.CustomABI do end defp check_smart_contract_address(%Changeset{changes: %{address_hash: address_hash}} = custom_abi) do - if Chain.is_address_hash_is_smart_contract?(address_hash) do - custom_abi - else - add_error(custom_abi, :address_hash, "Address is not a smart contract") - end + check_smart_contract_address_inner(custom_abi, address_hash) end defp check_smart_contract_address(%Changeset{data: %{address_hash: address_hash}} = custom_abi) do + check_smart_contract_address_inner(custom_abi, address_hash) + end + + defp check_smart_contract_address(custom_abi), do: custom_abi + + defp check_smart_contract_address_inner(changeset, address_hash) do if Chain.is_address_hash_is_smart_contract?(address_hash) do - custom_abi + changeset else - add_error(custom_abi, :address_hash, "Address is not a smart contract") + add_error(changeset, :address_hash, "Address is not a smart contract") end end - defp check_smart_contract_address(custom_abi), do: custom_abi - defp validate_custom_abi(%Changeset{changes: %{given_abi: given_abi, abi_validating_error: error}} = custom_abi) do custom_abi |> add_error(:abi, error) @@ -130,7 +130,7 @@ defmodule Explorer.Account.CustomABI do if identity_id |> custom_abis_by_identity_id_query() |> limit(@max_abis_per_account) - |> Repo.aggregate(:count, :id) >= @max_abis_per_account do + |> Repo.account_repo().aggregate(:count, :id) >= @max_abis_per_account do add_error(custom_abi, :name, "Max #{@max_abis_per_account} ABIs per account") else custom_abi @@ -142,7 +142,7 @@ defmodule Explorer.Account.CustomABI do def create(attrs) do %__MODULE__{} |> changeset(attrs) - |> Repo.insert() + |> Repo.account_repo().insert() end def custom_abis_by_identity_id_query(id) when not is_nil(id) do @@ -173,7 +173,7 @@ defmodule Explorer.Account.CustomABI do when not is_nil(identity_id) and not is_nil(address_hash) do address_hash |> custom_abi_by_identity_id_and_address_hash_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_custom_abi_by_identity_id_and_address_hash(_, _), do: nil @@ -181,7 +181,7 @@ defmodule Explorer.Account.CustomABI do def get_custom_abi_by_id_and_identity_id(id, identity_id) when not is_nil(id) and not is_nil(identity_id) do id |> custom_abi_by_id_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_custom_abi_by_id_and_identity_id(_, _), do: nil @@ -189,7 +189,7 @@ defmodule Explorer.Account.CustomABI do def get_custom_abis_by_identity_id(id) when not is_nil(id) do id |> custom_abis_by_identity_id_query() - |> Repo.all() + |> Repo.account_repo().all() end def get_custom_abis_by_identity_id(_), do: nil @@ -197,7 +197,7 @@ defmodule Explorer.Account.CustomABI do def delete(id, identity_id) when not is_nil(id) and not is_nil(identity_id) do id |> custom_abi_by_id_and_identity_id_query(identity_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete(_, _), do: nil @@ -207,7 +207,7 @@ defmodule Explorer.Account.CustomABI do false <- is_nil(custom_abi) do custom_abi |> changeset(attrs) - |> Repo.update() + |> Repo.account_repo().update() else true -> {:error, %{reason: :item_not_found}} diff --git a/apps/explorer/lib/explorer/account/identity.ex b/apps/explorer/lib/explorer/account/identity.ex index 3c39533459..49e75cc6a0 100644 --- a/apps/explorer/lib/explorer/account/identity.ex +++ b/apps/explorer/lib/explorer/account/identity.ex @@ -16,8 +16,10 @@ defmodule Explorer.Account.Identity do field(:name, :string) field(:nickname, :string) field(:avatar, :string) + has_many(:tag_addresses, TagAddress) has_many(:watchlists, Watchlist) + belongs_to(:plan, Plan) timestamps() diff --git a/apps/explorer/lib/explorer/account/notifier/email.ex b/apps/explorer/lib/explorer/account/notifier/email.ex index 03d4f51b94..35555e3169 100644 --- a/apps/explorer/lib/explorer/account/notifier/email.ex +++ b/apps/explorer/lib/explorer/account/notifier/email.ex @@ -85,9 +85,9 @@ defmodule Explorer.Account.Notifier.Email do do: name defp address_hash_string(%WatchlistNotification{ - watchlist_address: %WatchlistAddress{address: address} + watchlist_address: %WatchlistAddress{address_hash: address_hash} }), - do: hash_string(address.hash) + do: hash_string(address_hash) defp hash_string(hash) do "0x" <> Base.encode16(hash.bytes, case: :lower) @@ -114,7 +114,7 @@ defmodule Explorer.Account.Notifier.Email do end defp preload(notification) do - Repo.preload(notification, watchlist_address: [:address, watchlist: :identity]) + Repo.account_repo().preload(notification, watchlist_address: [watchlist: :identity]) end defp address_url(address_hash) do diff --git a/apps/explorer/lib/explorer/account/notifier/notify.ex b/apps/explorer/lib/explorer/account/notifier/notify.ex index 86a37ea346..b935442baa 100644 --- a/apps/explorer/lib/explorer/account/notifier/notify.ex +++ b/apps/explorer/lib/explorer/account/notifier/notify.ex @@ -64,7 +64,7 @@ defmodule Explorer.Account.Notifier.Notify do ) do notification |> query_notification(address) - |> Repo.all() + |> Repo.account_repo().all() |> case do [] -> save_and_send_notification(notification, address) _ -> :ok @@ -91,7 +91,7 @@ defmodule Explorer.Account.Notifier.Notify do end defp save_and_send_notification(%WatchlistNotification{} = notification, %WatchlistAddress{} = address) do - Repo.insert(notification) + Repo.account_repo().insert(notification) email = Email.compose(notification, address) @@ -143,6 +143,6 @@ defmodule Explorer.Account.Notifier.Notify do defp find_watchlists_addresses(%Explorer.Chain.Hash{} = address_hash) do query = from(wa in WatchlistAddress, where: wa.address_hash == ^address_hash) - Repo.all(query) + Repo.account_repo().all(query) end end diff --git a/apps/explorer/lib/explorer/account/public_tags_request.ex b/apps/explorer/lib/explorer/account/public_tags_request.ex index d62881b2ff..273d7b5b18 100644 --- a/apps/explorer/lib/explorer/account/public_tags_request.ex +++ b/apps/explorer/lib/explorer/account/public_tags_request.ex @@ -75,7 +75,7 @@ defmodule Explorer.Account.PublicTagsRequest do def create(attrs) do %__MODULE__{} |> changeset(Map.put(attrs, :request_type, "add")) - |> Repo.insert() + |> Repo.account_repo().insert() |> AirTable.submit() end @@ -90,7 +90,7 @@ defmodule Explorer.Account.PublicTagsRequest do if identity_id |> public_tags_requests_by_identity_id_query() |> limit(@max_public_tags_request_per_account) - |> Repo.aggregate(:count, :id) >= @max_public_tags_request_per_account do + |> Repo.account_repo().aggregate(:count, :id) >= @max_public_tags_request_per_account do request |> add_error(:tags, "Max #{@max_public_tags_request_per_account} public tags requests per account") else @@ -113,7 +113,7 @@ defmodule Explorer.Account.PublicTagsRequest do fragment("? && ?", public_tags_request.addresses, ^Enum.map(prepared_addresses, fn x -> x.bytes end)) ) |> limit(1) - |> Repo.one() + |> Repo.account_repo().one() now = DateTime.utc_now() @@ -192,7 +192,7 @@ defmodule Explorer.Account.PublicTagsRequest do def public_tags_request_by_id_and_identity_id_query(_, _), do: nil def get_public_tags_request_by_id_and_identity_id(id, identity_id) when not is_nil(id) and not is_nil(identity_id) do - id |> public_tags_request_by_id_and_identity_id_query(identity_id) |> Repo.one() + id |> public_tags_request_by_id_and_identity_id_query(identity_id) |> Repo.account_repo().one() end def get_public_tags_request_by_id_and_identity_id(_, _), do: nil @@ -200,7 +200,7 @@ defmodule Explorer.Account.PublicTagsRequest do def get_public_tags_requests_by_identity_id(id) when not is_nil(id) do id |> public_tags_requests_by_identity_id_query() - |> Repo.all() + |> Repo.account_repo().all() end def get_public_tags_requests_by_identity_id(_), do: nil @@ -208,7 +208,7 @@ defmodule Explorer.Account.PublicTagsRequest do def delete_public_tags_request(identity_id, id) when not is_nil(id) and not is_nil(identity_id) do id |> public_tags_request_by_id_and_identity_id_query(identity_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete_public_tags_request(_, _), do: nil @@ -216,7 +216,8 @@ defmodule Explorer.Account.PublicTagsRequest do def update(%{id: id, identity_id: identity_id} = attrs) do with public_tags_request <- get_public_tags_request_by_id_and_identity_id(id, identity_id), false <- is_nil(public_tags_request), - {:ok, changeset} <- public_tags_request |> changeset(Map.put(attrs, :request_type, "edit")) |> Repo.update() do + {:ok, changeset} <- + public_tags_request |> changeset(Map.put(attrs, :request_type, "edit")) |> Repo.account_repo().update() do AirTable.submit({:ok, changeset}) else true -> @@ -233,7 +234,7 @@ defmodule Explorer.Account.PublicTagsRequest do {:ok, changeset} <- public_tags_request |> changeset_without_constraints(%{request_type: "delete", remove_reason: remove_reason}) - |> Repo.update() do + |> Repo.account_repo().update() do case AirTable.submit({:ok, changeset}) do {:error, changeset} -> changeset diff --git a/apps/explorer/lib/explorer/account/tag_address.ex b/apps/explorer/lib/explorer/account/tag_address.ex index 6a3bd89c2b..49c2bcb63f 100644 --- a/apps/explorer/lib/explorer/account/tag_address.ex +++ b/apps/explorer/lib/explorer/account/tag_address.ex @@ -16,14 +16,9 @@ defmodule Explorer.Account.TagAddress do schema "account_tag_addresses" do field(:name, :string) + field(:address_hash, Hash.Address, null: false) belongs_to(:identity, Identity) - belongs_to(:address, Address, - foreign_key: :address_hash, - references: :hash, - type: Hash.Address - ) - timestamps() end @@ -42,30 +37,37 @@ defmodule Explorer.Account.TagAddress do |> validate_length(:name, min: 1, max: 35) |> unique_constraint([:identity_id, :address_hash], message: "Address tag already exists") |> check_existance_or_create_address() - |> foreign_key_constraint(:address_hash, message: "") |> tag_address_count_constraint() end def create(attrs) do %__MODULE__{} |> changeset(attrs) - |> Repo.insert() + |> Repo.account_repo().insert() end defp check_existance_or_create_address(%Changeset{changes: %{address_hash: address_hash}, valid?: true} = changeset) do + check_existance_or_create_address_inner(changeset, address_hash) + end + + defp check_existance_or_create_address(%Changeset{data: %{address_hash: address_hash}, valid?: true} = changeset) do + check_existance_or_create_address_inner(changeset, address_hash) + end + + defp check_existance_or_create_address(changeset), do: changeset + + defp check_existance_or_create_address_inner(changeset, address_hash) do with {:ok, hash} <- Hash.Address.cast(address_hash), {:ok, %Address{}} <- Chain.find_or_insert_address_from_hash(hash, []) do changeset end end - defp check_existance_or_create_address(changeset), do: changeset - def tag_address_count_constraint(%Changeset{changes: %{identity_id: identity_id}} = tag_address) do if identity_id |> tags_address_by_identity_id_query() |> limit(@max_tag_address_per_account) - |> Repo.aggregate(:count, :id) >= @max_tag_address_per_account do + |> Repo.account_repo().aggregate(:count, :id) >= @max_tag_address_per_account do tag_address |> add_error(:name, "Max #{@max_tag_address_per_account} tags per account") else @@ -86,7 +88,7 @@ defmodule Explorer.Account.TagAddress do def get_tags_address_by_identity_id(id) when not is_nil(id) do id |> tags_address_by_identity_id_query() - |> Repo.all() + |> Repo.account_repo().all() end def get_tags_address_by_identity_id(_), do: nil @@ -103,7 +105,7 @@ defmodule Explorer.Account.TagAddress do when not is_nil(address_hash) and not is_nil(identity_id) do address_hash |> tag_address_by_address_hash_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_tag_address_by_address_hash_and_identity_id(_, _), do: nil @@ -120,7 +122,7 @@ defmodule Explorer.Account.TagAddress do when not is_nil(tag_id) and not is_nil(identity_id) do tag_id |> tag_address_by_id_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_tag_address_by_id_and_identity_id_query(_, _), do: nil @@ -128,7 +130,7 @@ defmodule Explorer.Account.TagAddress do def delete(tag_id, identity_id) when not is_nil(tag_id) and not is_nil(identity_id) do tag_id |> tag_address_by_id_and_identity_id_query(identity_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete(_, _), do: nil @@ -136,7 +138,7 @@ defmodule Explorer.Account.TagAddress do def update(%{id: tag_id, identity_id: identity_id} = attrs) do with tag <- get_tag_address_by_id_and_identity_id_query(tag_id, identity_id), false <- is_nil(tag) do - tag |> changeset(attrs) |> Repo.update() + tag |> changeset(attrs) |> Repo.account_repo().update() else true -> {:error, %{reason: :item_not_found}} diff --git a/apps/explorer/lib/explorer/account/tag_transaction.ex b/apps/explorer/lib/explorer/account/tag_transaction.ex index b8d6d40538..4a2a87c160 100644 --- a/apps/explorer/lib/explorer/account/tag_transaction.ex +++ b/apps/explorer/lib/explorer/account/tag_transaction.ex @@ -9,20 +9,16 @@ defmodule Explorer.Account.TagTransaction do alias Ecto.Changeset alias Explorer.Account.Identity - alias Explorer.Chain.{Hash, Transaction} - alias Explorer.Repo + alias Explorer.{Chain, Repo} + alias Explorer.Chain.Hash @max_tag_transaction_per_account 15 schema "account_tag_transactions" do field(:name, :string) - belongs_to(:identity, Identity) + field(:tx_hash, Hash.Full, null: false) - belongs_to(:transaction, Transaction, - foreign_key: :tx_hash, - references: :hash, - type: Hash.Full - ) + belongs_to(:identity, Identity) timestamps() end @@ -41,21 +37,37 @@ defmodule Explorer.Account.TagTransaction do |> validate_required(@attrs, message: "Required") |> validate_length(:name, min: 1, max: 35) |> unique_constraint([:identity_id, :tx_hash], message: "Transaction tag already exists") - |> foreign_key_constraint(:tx_hash, message: "Transaction does not exist") |> tag_transaction_count_constraint() + |> check_transaction_existance() end def create(attrs) do %__MODULE__{} |> changeset(attrs) - |> Repo.insert() + |> Repo.account_repo().insert() + end + + defp check_transaction_existance(%Changeset{changes: %{tx_hash: tx_hash}} = changeset) do + check_transaction_existance_inner(changeset, tx_hash) + end + + defp check_transaction_existance(%Changeset{data: %{tx_hash: tx_hash}} = changeset) do + check_transaction_existance_inner(changeset, tx_hash) + end + + defp check_transaction_existance_inner(changeset, tx_hash) do + if match?({:ok, _}, Chain.hash_to_transaction(tx_hash)) do + changeset + else + add_error(changeset, :tx_hash, "Transaction does not exist") + end end def tag_transaction_count_constraint(%Changeset{changes: %{identity_id: identity_id}} = tag_transaction) do if identity_id |> tags_transaction_by_identity_id_query() |> limit(@max_tag_transaction_per_account) - |> Repo.aggregate(:count, :id) >= @max_tag_transaction_per_account do + |> Repo.account_repo().aggregate(:count, :id) >= @max_tag_transaction_per_account do tag_transaction |> add_error(:name, "Max #{@max_tag_transaction_per_account} tags per account") else @@ -76,7 +88,7 @@ defmodule Explorer.Account.TagTransaction do def get_tags_transaction_by_identity_id(id) when not is_nil(id) do id |> tags_transaction_by_identity_id_query() - |> Repo.all() + |> Repo.account_repo().all() end def get_tags_transaction_by_identity_id(_), do: nil @@ -93,7 +105,7 @@ defmodule Explorer.Account.TagTransaction do when not is_nil(address_hash) and not is_nil(identity_id) do address_hash |> tag_transaction_by_address_hash_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_tag_transaction_by_address_hash_and_identity_id(_, _), do: nil @@ -110,7 +122,7 @@ defmodule Explorer.Account.TagTransaction do when not is_nil(tag_id) and not is_nil(identity_id) do tag_id |> tag_transaction_by_id_and_identity_id_query(identity_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_tag_transaction_by_id_and_identity_id_query(_, _), do: nil @@ -118,7 +130,7 @@ defmodule Explorer.Account.TagTransaction do def delete(tag_id, identity_id) when not is_nil(tag_id) and not is_nil(identity_id) do tag_id |> tag_transaction_by_id_and_identity_id_query(identity_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete(_, _), do: nil @@ -126,7 +138,7 @@ defmodule Explorer.Account.TagTransaction do def update(%{id: tag_id, identity_id: identity_id} = attrs) do with tag <- get_tag_transaction_by_id_and_identity_id_query(tag_id, identity_id), false <- is_nil(tag) do - tag |> changeset(attrs) |> Repo.update() + tag |> changeset(attrs) |> Repo.account_repo().update() else true -> {:error, %{reason: :item_not_found}} diff --git a/apps/explorer/lib/explorer/account/watchlist.ex b/apps/explorer/lib/explorer/account/watchlist.ex index 8fe02ae43a..cd6998b83f 100644 --- a/apps/explorer/lib/explorer/account/watchlist.ex +++ b/apps/explorer/lib/explorer/account/watchlist.ex @@ -14,7 +14,6 @@ defmodule Explorer.Account.Watchlist do field(:name, :string) belongs_to(:identity, Identity) has_many(:watchlist_addresses, WatchlistAddress) - has_many(:addresses, through: [:watchlist_addresses, :address]) timestamps() end diff --git a/apps/explorer/lib/explorer/account/watchlist_address.ex b/apps/explorer/lib/explorer/account/watchlist_address.ex index 65abb8b69e..e65084a4f9 100644 --- a/apps/explorer/lib/explorer/account/watchlist_address.ex +++ b/apps/explorer/lib/explorer/account/watchlist_address.ex @@ -11,13 +11,14 @@ defmodule Explorer.Account.WatchlistAddress do alias Explorer.Account.Notifier.ForbiddenAddress alias Explorer.Account.Watchlist alias Explorer.{Chain, Repo} - alias Explorer.Chain.{Address, Hash} + alias Explorer.Chain.{Address, Hash, Wei} @max_watchlist_addresses_per_account 10 schema "account_watchlist_addresses" do field(:name, :string) - belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address) + field(:address_hash, Hash.Address, null: false) + belongs_to(:watchlist, Watchlist) field(:watch_coin_input, :boolean, default: true) @@ -33,6 +34,8 @@ defmodule Explorer.Account.WatchlistAddress do field(:notify_feed, :boolean) field(:notify_inapp, :boolean) + field(:fetched_coin_balance, Wei, virtual: true) + timestamps() end @@ -51,21 +54,20 @@ defmodule Explorer.Account.WatchlistAddress do |> validate_required([:name, :address_hash, :watchlist_id], message: "Required") |> unique_constraint([:watchlist_id, :address_hash], message: "Address already added to the watch list") |> check_address() - |> foreign_key_constraint(:address_hash, message: "") |> watchlist_address_count_constraint() end def create(attrs) do %__MODULE__{} |> changeset(attrs) - |> Repo.insert() + |> Repo.account_repo().insert() end def watchlist_address_count_constraint(%Changeset{changes: %{watchlist_id: watchlist_id}} = watchlist_address) do if watchlist_id |> watchlist_addresses_by_watchlist_id_query() |> limit(@max_watchlist_addresses_per_account) - |> Repo.aggregate(:count, :id) >= @max_watchlist_addresses_per_account do + |> Repo.account_repo().aggregate(:count, :id) >= @max_watchlist_addresses_per_account do watchlist_address |> add_error(:name, "Max #{@max_watchlist_addresses_per_account} watch list addresses per account") else @@ -76,6 +78,16 @@ defmodule Explorer.Account.WatchlistAddress do def watchlist_address_count_constraint(changeset), do: changeset defp check_address(%Changeset{changes: %{address_hash: address_hash}, valid?: true} = changeset) do + check_address_inner(changeset, address_hash) + end + + defp check_address(%Changeset{data: %{address_hash: address_hash}, valid?: true} = changeset) do + check_address_inner(changeset, address_hash) + end + + defp check_address(changeset), do: changeset + + defp check_address_inner(changeset, address_hash) do with {:ok, address_hash} <- ForbiddenAddress.check(address_hash), {:ok, %Address{}} <- Chain.find_or_insert_address_from_hash(address_hash, []) do changeset @@ -88,8 +100,6 @@ defmodule Explorer.Account.WatchlistAddress do end end - defp check_address(changeset), do: changeset - def watchlist_addresses_by_watchlist_id_query(watchlist_id) when not is_nil(watchlist_id) do __MODULE__ |> where([wl_address], wl_address.watchlist_id == ^watchlist_id) @@ -109,7 +119,7 @@ defmodule Explorer.Account.WatchlistAddress do when not is_nil(watchlist_address_id) and not is_nil(watchlist_id) do watchlist_address_id |> watchlist_address_by_id_and_watchlist_id_query(watchlist_id) - |> Repo.one() + |> Repo.account_repo().one() end def get_watchlist_address_by_id_and_watchlist_id(_, _), do: nil @@ -118,7 +128,7 @@ defmodule Explorer.Account.WatchlistAddress do when not is_nil(watchlist_address_id) and not is_nil(watchlist_id) do watchlist_address_id |> watchlist_address_by_id_and_watchlist_id_query(watchlist_id) - |> Repo.delete_all() + |> Repo.account_repo().delete_all() end def delete(_, _), do: nil @@ -128,7 +138,7 @@ defmodule Explorer.Account.WatchlistAddress do false <- is_nil(watchlist_address) do watchlist_address |> changeset(attrs) - |> Repo.update() + |> Repo.account_repo().update() else true -> {:error, %{reason: :item_not_found}} @@ -136,4 +146,19 @@ defmodule Explorer.Account.WatchlistAddress do end def get_max_watchlist_addresses_count, do: @max_watchlist_addresses_per_account + + def preload_address_fetched_coin_balance(%Watchlist{watchlist_addresses: watchlist_addresses} = watchlist) do + w_addresses = + Enum.map(watchlist_addresses, fn wa -> + preload_address_fetched_coin_balance(wa) + end) + + %Watchlist{watchlist | watchlist_addresses: w_addresses} + end + + def preload_address_fetched_coin_balance(%__MODULE__{address_hash: address_hash} = watchlist_address) do + %__MODULE__{watchlist_address | fetched_coin_balance: address_hash |> Address.fetched_coin_balance() |> Repo.one()} + end + + def preload_address_fetched_coin_balance(watchlist), do: watchlist end diff --git a/apps/explorer/lib/explorer/account/watchlist_notification.ex b/apps/explorer/lib/explorer/account/watchlist_notification.ex index a5731a4f2a..7de98721db 100644 --- a/apps/explorer/lib/explorer/account/watchlist_notification.ex +++ b/apps/explorer/lib/explorer/account/watchlist_notification.ex @@ -9,12 +9,7 @@ defmodule Explorer.Account.WatchlistNotification do import Ecto.Changeset alias Explorer.Account.WatchlistAddress - - alias Explorer.Chain.{ - Address, - Hash, - Transaction - } + alias Explorer.Chain.Hash schema "account_watchlist_notifications" do field(:amount, :decimal) @@ -29,27 +24,9 @@ defmodule Explorer.Account.WatchlistNotification do belongs_to(:watchlist_address, WatchlistAddress) - belongs_to( - :from_address, - Address, - foreign_key: :from_address_hash, - references: :hash, - type: Hash.Address - ) - - belongs_to( - :to_address, - Address, - foreign_key: :to_address_hash, - references: :hash, - type: Hash.Address - ) - - belongs_to(:transaction, Transaction, - foreign_key: :transaction_hash, - references: :hash, - type: Hash.Full - ) + field(:from_address_hash, Hash.Address) + field(:to_address_hash, Hash.Address) + field(:transaction_hash, Hash.Full) timestamps() end diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index c42370c0e5..eea99e8573 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -43,6 +43,7 @@ defmodule Explorer.Application do base_children = [ Explorer.Repo, Explorer.Repo.Replica1, + Explorer.Repo.Account, Supervisor.child_spec({SpandexDatadog.ApiServer, datadog_opts()}, id: SpandexDatadog.ApiServer), Supervisor.child_spec({Task.Supervisor, name: Explorer.HistoryTaskSupervisor}, id: Explorer.HistoryTaskSupervisor), Supervisor.child_spec({Task.Supervisor, name: Explorer.MarketTaskSupervisor}, id: Explorer.MarketTaskSupervisor), diff --git a/apps/explorer/lib/explorer/chain/address.ex b/apps/explorer/lib/explorer/chain/address.ex index 1a71d3e224..163dd66f8d 100644 --- a/apps/explorer/lib/explorer/chain/address.ex +++ b/apps/explorer/lib/explorer/chain/address.ex @@ -259,6 +259,12 @@ defmodule Explorer.Chain.Address do ) end + def fetched_coin_balance(address_hash) when not is_nil(address_hash) do + Address + |> where([address], address.hash == ^address_hash) + |> select([address], address.fetched_coin_balance) + end + defimpl String.Chars do @doc """ Uses `hash` as string representation, formatting it according to the eip-55 specification diff --git a/apps/explorer/lib/explorer/repo.ex b/apps/explorer/lib/explorer/repo.ex index 14a48d9d33..c64db8b97d 100644 --- a/apps/explorer/lib/explorer/repo.ex +++ b/apps/explorer/lib/explorer/repo.ex @@ -128,10 +128,54 @@ defmodule Explorer.Repo do def replica, do: Explorer.Repo.Replica1 end + def account_repo, do: Explorer.Repo.Account + defmodule Replica1 do use Ecto.Repo, otp_app: :explorer, adapter: Ecto.Adapters.Postgres, read_only: true + + def init(_, opts) do + db_url = Application.get_env(:explorer, Explorer.Repo.Replica1)[:url] + repo_conf = Application.get_env(:explorer, Explorer.Repo.Replica1) + + merged = + %{url: db_url} + |> ConfigHelper.get_db_config() + |> Keyword.merge(repo_conf, fn + _key, v1, nil -> v1 + _key, nil, v2 -> v2 + _, _, v2 -> v2 + end) + + Application.put_env(:explorer, Explorer.Repo.Replica1, merged) + + {:ok, Keyword.put(opts, :url, db_url)} + end + end + + defmodule Account do + use Ecto.Repo, + otp_app: :explorer, + adapter: Ecto.Adapters.Postgres + + def init(_, opts) do + db_url = Application.get_env(:explorer, Explorer.Repo.Account)[:url] + repo_conf = Application.get_env(:explorer, Explorer.Repo.Account) + + merged = + %{url: db_url} + |> ConfigHelper.get_db_config() + |> Keyword.merge(repo_conf, fn + _key, v1, nil -> v1 + _key, nil, v2 -> v2 + _, _, v2 -> v2 + end) + + Application.put_env(:explorer, Explorer.Repo.Account, merged) + + {:ok, Keyword.put(opts, :url, db_url)} + end end end diff --git a/apps/explorer/lib/explorer/third_party_integrations/airtable.ex b/apps/explorer/lib/explorer/third_party_integrations/airtable.ex index 93137f3bc7..cd7e1e0f88 100644 --- a/apps/explorer/lib/explorer/third_party_integrations/airtable.ex +++ b/apps/explorer/lib/explorer/third_party_integrations/airtable.ex @@ -12,7 +12,7 @@ defmodule Explorer.ThirdPartyIntegrations.AirTable do if Mix.env() == :test do new_request |> PublicTagsRequest.changeset(%{request_id: "123"}) - |> Repo.update() + |> Repo.account_repo().update() input else @@ -33,7 +33,7 @@ defmodule Explorer.ThirdPartyIntegrations.AirTable do new_request |> PublicTagsRequest.changeset(%{request_id: request_id}) - |> Repo.update() + |> Repo.account_repo().update() input diff --git a/apps/explorer/lib/release_tasks.ex b/apps/explorer/lib/release_tasks.ex index 8d5a1b486c..1fcdc7fca8 100644 --- a/apps/explorer/lib/release_tasks.ex +++ b/apps/explorer/lib/release_tasks.ex @@ -14,7 +14,7 @@ defmodule Explorer.ReleaseTasks do :ecto_sql ] - @repos Application.compile_env(:blockscout, :ecto_repos, [Explorer.Repo]) + @repos Application.compile_env(:blockscout, :ecto_repos, [Explorer.Repo, Explorer.Repo.Account]) def create_and_migrate do start_services() diff --git a/apps/explorer/priv/repo/migrations/20211031164954_create_account_identities.exs b/apps/explorer/priv/account/migrations/20211031164954_create_account_identities.exs similarity index 73% rename from apps/explorer/priv/repo/migrations/20211031164954_create_account_identities.exs rename to apps/explorer/priv/account/migrations/20211031164954_create_account_identities.exs index 1da855996a..fb571247f0 100644 --- a/apps/explorer/priv/repo/migrations/20211031164954_create_account_identities.exs +++ b/apps/explorer/priv/account/migrations/20211031164954_create_account_identities.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.CreateAccountIdentities do +defmodule Explorer.Repo.Account.Migrations.CreateAccountIdentities do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20211105114502_create_account_watchlists.exs b/apps/explorer/priv/account/migrations/20211105114502_create_account_watchlists.exs similarity index 81% rename from apps/explorer/priv/repo/migrations/20211105114502_create_account_watchlists.exs rename to apps/explorer/priv/account/migrations/20211105114502_create_account_watchlists.exs index 58924200fe..2e7c93f3cc 100644 --- a/apps/explorer/priv/repo/migrations/20211105114502_create_account_watchlists.exs +++ b/apps/explorer/priv/account/migrations/20211105114502_create_account_watchlists.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.CreateAccountWatchlists do +defmodule Explorer.Repo.Account.Migrations.CreateAccountWatchlists do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20211105130907_create_account_watchlist_addresses.exs b/apps/explorer/priv/account/migrations/20211105130907_create_account_watchlist_addresses.exs similarity index 85% rename from apps/explorer/priv/repo/migrations/20211105130907_create_account_watchlist_addresses.exs rename to apps/explorer/priv/account/migrations/20211105130907_create_account_watchlist_addresses.exs index 98f0aa9ac1..ef51c1850e 100644 --- a/apps/explorer/priv/repo/migrations/20211105130907_create_account_watchlist_addresses.exs +++ b/apps/explorer/priv/account/migrations/20211105130907_create_account_watchlist_addresses.exs @@ -1,10 +1,10 @@ -defmodule Explorer.Repo.Migrations.CreateAccountWatchlistAddresses do +defmodule Explorer.Repo.Account.Migrations.CreateAccountWatchlistAddresses do use Ecto.Migration def change do create table(:account_watchlist_addresses) do add(:name, :string) - add(:address_hash, references(:addresses, column: :hash, type: :bytea, on_delete: :delete_all)) + add(:address_hash, :bytea, null: false) add(:watchlist_id, references(:account_watchlists, on_delete: :delete_all)) add(:watch_coin_input, :boolean, default: true) add(:watch_coin_output, :boolean, default: true) diff --git a/apps/explorer/priv/repo/migrations/20211127212336_create_account_watchlist_notifications.exs b/apps/explorer/priv/account/migrations/20211127212336_create_account_watchlist_notifications.exs similarity index 67% rename from apps/explorer/priv/repo/migrations/20211127212336_create_account_watchlist_notifications.exs rename to apps/explorer/priv/account/migrations/20211127212336_create_account_watchlist_notifications.exs index 8310df5dfc..7d4af566fe 100644 --- a/apps/explorer/priv/repo/migrations/20211127212336_create_account_watchlist_notifications.exs +++ b/apps/explorer/priv/account/migrations/20211127212336_create_account_watchlist_notifications.exs @@ -1,15 +1,15 @@ -defmodule Explorer.Repo.Migrations.CreateAccountWatchlistNotifications do +defmodule Explorer.Repo.Account.Migrations.CreateAccountWatchlistNotifications do use Ecto.Migration def change do create table(:account_watchlist_notifications) do add(:watchlist_address_id, references(:account_watchlist_addresses, on_delete: :delete_all)) - add(:transaction_hash, references(:transactions, column: :hash, type: :bytea, on_delete: :delete_all)) + add(:transaction_hash, :bytea) - add(:from_address_hash, references(:addresses, column: :hash, type: :bytea, on_delete: :delete_all)) + add(:from_address_hash, :bytea) - add(:to_address_hash, references(:addresses, column: :hash, type: :bytea, on_delete: :delete_all)) + add(:to_address_hash, :bytea) add(:direction, :string) add(:name, :string) diff --git a/apps/explorer/priv/repo/migrations/20211205220414_add_email_and_name_to_account_identity.exs b/apps/explorer/priv/account/migrations/20211205220414_add_email_and_name_to_account_identity.exs similarity index 67% rename from apps/explorer/priv/repo/migrations/20211205220414_add_email_and_name_to_account_identity.exs rename to apps/explorer/priv/account/migrations/20211205220414_add_email_and_name_to_account_identity.exs index bf87606d6c..0633e0dbae 100644 --- a/apps/explorer/priv/repo/migrations/20211205220414_add_email_and_name_to_account_identity.exs +++ b/apps/explorer/priv/account/migrations/20211205220414_add_email_and_name_to_account_identity.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddEmailToAccountIdentity do +defmodule Explorer.Repo.Account.Migrations.AddEmailToAccountIdentity do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220212222222_create_account_tag_addresses.exs b/apps/explorer/priv/account/migrations/20220212222222_create_account_tag_addresses.exs similarity index 64% rename from apps/explorer/priv/repo/migrations/20220212222222_create_account_tag_addresses.exs rename to apps/explorer/priv/account/migrations/20220212222222_create_account_tag_addresses.exs index 0a306516ff..df0074041e 100644 --- a/apps/explorer/priv/repo/migrations/20220212222222_create_account_tag_addresses.exs +++ b/apps/explorer/priv/account/migrations/20220212222222_create_account_tag_addresses.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.CreateAccountTagAddresses do +defmodule Explorer.Repo.Account.Migrations.CreateAccountTagAddresses do use Ecto.Migration def change do @@ -6,10 +6,7 @@ defmodule Explorer.Repo.Migrations.CreateAccountTagAddresses do add(:name, :string) add(:identity_id, references(:account_identities, on_delete: :delete_all)) - add( - :address_hash, - references(:addresses, column: :hash, type: :bytea, on_delete: :delete_all) - ) + add(:address_hash, :bytea, null: false) timestamps() end diff --git a/apps/explorer/priv/repo/migrations/20220313133333_create_account_tag_transactions.exs b/apps/explorer/priv/account/migrations/20220313133333_create_account_tag_transactions.exs similarity index 64% rename from apps/explorer/priv/repo/migrations/20220313133333_create_account_tag_transactions.exs rename to apps/explorer/priv/account/migrations/20220313133333_create_account_tag_transactions.exs index 49facab8c0..ba6fa338b9 100644 --- a/apps/explorer/priv/repo/migrations/20220313133333_create_account_tag_transactions.exs +++ b/apps/explorer/priv/account/migrations/20220313133333_create_account_tag_transactions.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.CreateAccountTagTransactions do +defmodule Explorer.Repo.Account.Migrations.CreateAccountTagTransactions do use Ecto.Migration def change do @@ -6,10 +6,7 @@ defmodule Explorer.Repo.Migrations.CreateAccountTagTransactions do add(:name, :string) add(:identity_id, references(:account_identities, on_delete: :delete_all)) - add( - :tx_hash, - references(:transactions, column: :hash, type: :bytea, on_delete: :delete_all) - ) + add(:tx_hash, :bytea, null: false) timestamps() end diff --git a/apps/explorer/priv/repo/migrations/20220324213333_add_subject_to_watchlist_notifications.exs b/apps/explorer/priv/account/migrations/20220324213333_add_subject_to_watchlist_notifications.exs similarity index 64% rename from apps/explorer/priv/repo/migrations/20220324213333_add_subject_to_watchlist_notifications.exs rename to apps/explorer/priv/account/migrations/20220324213333_add_subject_to_watchlist_notifications.exs index 7f644aaf87..6ff8a359ba 100644 --- a/apps/explorer/priv/repo/migrations/20220324213333_add_subject_to_watchlist_notifications.exs +++ b/apps/explorer/priv/account/migrations/20220324213333_add_subject_to_watchlist_notifications.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddSubjectToWatchlistNotifications do +defmodule Explorer.Repo.Account.Migrations.AddSubjectToWatchlistNotifications do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220407134152_add_api_keys_and_plans_tables.exs b/apps/explorer/priv/account/migrations/20220407134152_add_api_keys_and_plans_tables.exs similarity index 93% rename from apps/explorer/priv/repo/migrations/20220407134152_add_api_keys_and_plans_tables.exs rename to apps/explorer/priv/account/migrations/20220407134152_add_api_keys_and_plans_tables.exs index 245a077c43..11f23ffd61 100644 --- a/apps/explorer/priv/repo/migrations/20220407134152_add_api_keys_and_plans_tables.exs +++ b/apps/explorer/priv/account/migrations/20220407134152_add_api_keys_and_plans_tables.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddApiKeysAndPlansTables do +defmodule Explorer.Repo.Account.Migrations.AddApiKeysAndPlansTables do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220510094118_add_custom_abis_table.exs b/apps/explorer/priv/account/migrations/20220510094118_add_custom_abis_table.exs similarity index 74% rename from apps/explorer/priv/repo/migrations/20220510094118_add_custom_abis_table.exs rename to apps/explorer/priv/account/migrations/20220510094118_add_custom_abis_table.exs index a08b1cf365..a248c79458 100644 --- a/apps/explorer/priv/repo/migrations/20220510094118_add_custom_abis_table.exs +++ b/apps/explorer/priv/account/migrations/20220510094118_add_custom_abis_table.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddCustomAbisTable do +defmodule Explorer.Repo.Account.Migrations.AddCustomAbisTable do use Ecto.Migration def change do @@ -6,7 +6,7 @@ defmodule Explorer.Repo.Migrations.AddCustomAbisTable do add(:id, :serial, null: false, primary_key: true) add(:identity_id, references(:account_identities, column: :id, on_delete: :delete_all), null: false) add(:name, :string, null: false) - add(:address_hash, references(:addresses, column: :hash, type: :bytea, on_delete: :delete_all), null: false) + add(:address_hash, :bytea, null: false) add(:abi, :jsonb, null: false) timestamps() diff --git a/apps/explorer/priv/repo/migrations/20220606194836_add_account_public_tags_requests.exs b/apps/explorer/priv/account/migrations/20220606194836_add_account_public_tags_requests.exs similarity index 88% rename from apps/explorer/priv/repo/migrations/20220606194836_add_account_public_tags_requests.exs rename to apps/explorer/priv/account/migrations/20220606194836_add_account_public_tags_requests.exs index f1d95e9d01..dd0a9896b0 100644 --- a/apps/explorer/priv/repo/migrations/20220606194836_add_account_public_tags_requests.exs +++ b/apps/explorer/priv/account/migrations/20220606194836_add_account_public_tags_requests.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddAccountPublicTagsRequests do +defmodule Explorer.Repo.Account.Migrations.AddAccountPublicTagsRequests do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220620182600_add_account_identity_fields.exs b/apps/explorer/priv/account/migrations/20220620182600_add_account_identity_fields.exs similarity index 71% rename from apps/explorer/priv/repo/migrations/20220620182600_add_account_identity_fields.exs rename to apps/explorer/priv/account/migrations/20220620182600_add_account_identity_fields.exs index 2966c9dc59..1c7b13535f 100644 --- a/apps/explorer/priv/repo/migrations/20220620182600_add_account_identity_fields.exs +++ b/apps/explorer/priv/account/migrations/20220620182600_add_account_identity_fields.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddAccountIdentityFields do +defmodule Explorer.Repo.Account.Migrations.AddAccountIdentityFields do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220624142547_add_unique_constraints.exs b/apps/explorer/priv/account/migrations/20220624142547_add_unique_constraints.exs similarity index 81% rename from apps/explorer/priv/repo/migrations/20220624142547_add_unique_constraints.exs rename to apps/explorer/priv/account/migrations/20220624142547_add_unique_constraints.exs index a67b5dadbd..53293983d4 100644 --- a/apps/explorer/priv/repo/migrations/20220624142547_add_unique_constraints.exs +++ b/apps/explorer/priv/account/migrations/20220624142547_add_unique_constraints.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.AddUniqueConstraints do +defmodule Explorer.Repo.Account.Migrations.AddUniqueConstraints do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220811195240_migrate_public_tags_addresses_to_array.exs b/apps/explorer/priv/account/migrations/20220705195240_migrate_public_tags_addresses_to_array.exs similarity index 91% rename from apps/explorer/priv/repo/migrations/20220811195240_migrate_public_tags_addresses_to_array.exs rename to apps/explorer/priv/account/migrations/20220705195240_migrate_public_tags_addresses_to_array.exs index 0fa5f0e050..1282e2166c 100644 --- a/apps/explorer/priv/repo/migrations/20220811195240_migrate_public_tags_addresses_to_array.exs +++ b/apps/explorer/priv/account/migrations/20220705195240_migrate_public_tags_addresses_to_array.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.MigratePublicTagsAddressesToArray do +defmodule Explorer.Repo.Account.Migrations.MigratePublicTagsAddressesToArray do use Ecto.Migration def change do diff --git a/apps/explorer/priv/repo/migrations/20220729075714_guardiandb.exs b/apps/explorer/priv/account/migrations/20220729075714_guardiandb.exs similarity index 83% rename from apps/explorer/priv/repo/migrations/20220729075714_guardiandb.exs rename to apps/explorer/priv/account/migrations/20220729075714_guardiandb.exs index 21c3f9aead..fc058ff73b 100644 --- a/apps/explorer/priv/repo/migrations/20220729075714_guardiandb.exs +++ b/apps/explorer/priv/account/migrations/20220729075714_guardiandb.exs @@ -1,4 +1,4 @@ -defmodule Explorer.Repo.Migrations.CreateGuardianDBTokensTable do +defmodule Explorer.Repo.Account.Migrations.CreateGuardianDBTokensTable do use Ecto.Migration def change do diff --git a/apps/explorer/priv/account/migrations/20220901135656_copy_account_data.exs b/apps/explorer/priv/account/migrations/20220901135656_copy_account_data.exs new file mode 100644 index 0000000000..2824c36607 --- /dev/null +++ b/apps/explorer/priv/account/migrations/20220901135656_copy_account_data.exs @@ -0,0 +1,92 @@ +defmodule Explorer.Repo.Account.Migrations.CopyAccountData do + use Ecto.Migration + + def change do + execute("CREATE EXTENSION dblink;") + execute("SELECT dblink_connect('db_to_copy_from', '#{System.get_env("DATABASE_URL")}');") + + execute( + "INSERT INTO account_identities + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_identities') + row(id bigint, uid character varying(255), inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone, email character varying(255), name character varying(255), plan_id bigint, nickname character varying(255), avatar text);" + ) + + # execute("INSERT INTO account_api_plans + # SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_api_plans') + # row(id integer, max_req_per_second smallint, name character varying(255), inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);") + + execute( + "INSERT INTO account_api_keys + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_api_keys') + row(identity_id bigint, name character varying(255), value uuid, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_custom_abis + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_custom_abis') + row(id integer, identity_id bigint, name character varying(255), address_hash bytea, abi jsonb, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_public_tags_requests + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_public_tags_requests') + row(id integer, identity_id bigint, full_name character varying(255), email character varying(255), company character varying(255), website character varying(255), tags character varying(255), description text, additional_comment character varying(255), request_type character varying(255), is_owner boolean, remove_reason text, request_id character varying(255), inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone, addresses bytea[]);" + ) + + execute( + "INSERT INTO account_tag_addresses + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_tag_addresses') + row(id integer, name character varying(255), identity_id bigint, address_hash bytea, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_tag_transactions + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_tag_transactions') + row(id integer, name character varying(255), identity_id bigint, tx_hash bytea, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_watchlists + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_watchlists') + row(id bigint, name character varying(255), identity_id bigint, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_watchlist_addresses + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_watchlist_addresses') + row(id bigint, name character varying(255), address_hash bytea, watchlist_id bigint, watch_coin_input boolean, watch_coin_output boolean, watch_erc_20_input boolean, watch_erc_20_output boolean, watch_erc_721_input boolean, watch_erc_721_output boolean, watch_erc_1155_input boolean, watch_erc_1155_output boolean, notify_email boolean, notify_epns boolean, notify_feed boolean, notify_inapp boolean, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute( + "INSERT INTO account_watchlist_notifications + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM account_watchlist_notifications') + row(id bigint, watchlist_address_id bigint, transaction_hash bytea, from_address_hash bytea, to_address_hash bytea, direction character varying(255), name character varying(255), type character varying(255), method character varying(255), block_number integer, amount numeric, tx_fee numeric, viewed_at timestamp without time zone, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone, subject character varying(255));" + ) + + execute( + "INSERT INTO guardian_tokens + SELECT * FROM dblink('db_to_copy_from', 'SELECT * FROM guardian_tokens') + row(jti character varying(255), aud character varying(255), typ character varying(255), iss character varying(255), sub character varying(255), exp bigint, jwt text, claims jsonb, inserted_at timestamp(0) without time zone, updated_at timestamp(0) without time zone);" + ) + + execute("SELECT dblink_disconnect('db_to_copy_from');") + execute("DROP EXTENSION dblink;") + + # update sequence id counter + execute("SELECT setval('account_identities_id_seq', (SELECT MAX(id) FROM account_identities)+1);") + execute("SELECT setval('account_custom_abis_id_seq', (SELECT MAX(id) FROM account_custom_abis)+1);") + + execute( + "SELECT setval('account_public_tags_requests_id_seq', (SELECT MAX(id) FROM account_public_tags_requests)+1);" + ) + + execute("SELECT setval('account_tag_addresses_id_seq', (SELECT MAX(id) FROM account_tag_addresses)+1);") + execute("SELECT setval('account_tag_transactions_id_seq', (SELECT MAX(id) FROM account_tag_transactions)+1);") + execute("SELECT setval('account_watchlists_id_seq', (SELECT MAX(id) FROM account_watchlists)+1);") + execute("SELECT setval('account_watchlist_addresses_id_seq', (SELECT MAX(id) FROM account_watchlist_addresses)+1);") + + execute( + "SELECT setval('account_watchlist_notifications_id_seq', (SELECT MAX(id) FROM account_watchlist_notifications)+1);" + ) + end +end diff --git a/apps/explorer/test/explorer/account/notify/email_test.exs b/apps/explorer/test/explorer/account/notify/email_test.exs index aff4baf42e..34e5a57ad6 100644 --- a/apps/explorer/test/explorer/account/notify/email_test.exs +++ b/apps/explorer/test/explorer/account/notify/email_test.exs @@ -60,7 +60,6 @@ defmodule Explorer.Account.Notify.EmailTest do watchlist_address = %WatchlistAddress{ name: "wallet", watchlist: watchlist, - address: to_address, address_hash: to_hash, watch_coin_input: true, watch_coin_output: true, diff --git a/apps/explorer/test/explorer/account/notify/notify_test.exs b/apps/explorer/test/explorer/account/notify/notify_test.exs index 1f97769a16..4d169f04d6 100644 --- a/apps/explorer/test/explorer/account/notify/notify_test.exs +++ b/apps/explorer/test/explorer/account/notify/notify_test.exs @@ -46,7 +46,7 @@ defmodule Explorer.Account.Notify.NotifyTest do wn = WatchlistNotification |> first - |> Repo.one() + |> Repo.account_repo().one() assert notify == [[:ok]] @@ -55,11 +55,11 @@ defmodule Explorer.Account.Notify.NotifyTest do test "when address apears in watchlist" do wa = - %WatchlistAddress{ - address: address - } = insert(:account_watchlist_address) + %WatchlistAddress{address_hash: address_hash} = + build(:account_watchlist_address) + |> Repo.account_repo().insert!() - _watchlist_address = Repo.preload(wa, :address, watchlist: :identity) + _watchlist_address = Repo.preload(wa, watchlist: :identity) tx = %Transaction{ @@ -67,7 +67,7 @@ defmodule Explorer.Account.Notify.NotifyTest do to_address: _to_address, block_number: _block_number, hash: _tx_hash - } = with_block(insert(:transaction, to_address: address)) + } = with_block(insert(:transaction, to_address: %Chain.Address{hash: address_hash})) {_, fee} = Chain.fee(tx, :gwei) amount = Wei.to(tx.value, :ether) @@ -76,7 +76,7 @@ defmodule Explorer.Account.Notify.NotifyTest do wn = WatchlistNotification |> first - |> Repo.one() + |> Repo.account_repo().one() assert notify == [[:ok]] diff --git a/apps/explorer/test/support/data_case.ex b/apps/explorer/test/support/data_case.ex index e12dd24a82..da18760983 100644 --- a/apps/explorer/test/support/data_case.ex +++ b/apps/explorer/test/support/data_case.ex @@ -34,9 +34,11 @@ defmodule Explorer.DataCase do ExVCR.Config.cassette_library_dir("test/support/fixture/vcr_cassettes") :ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo) + :ok = Ecto.Adapters.SQL.Sandbox.checkout(Explorer.Repo.Account) unless tags[:async] do Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, {:shared, self()}) + Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo.Account, {:shared, self()}) end Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.BlockNumber.child_id()) diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 4d2c0d184f..12d0d7301f 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -126,7 +126,6 @@ defmodule Explorer.Factory do def account_watchlist_factory do %Watchlist{ - name: "default", identity: build(:account_identity) } end @@ -140,10 +139,12 @@ defmodule Explorer.Factory do end def account_watchlist_address_factory do + hash = build(:address).hash + %WatchlistAddress{ name: "wallet", watchlist: build(:account_watchlist), - address: build(:address), + address_hash: hash, watch_coin_input: true, watch_coin_output: true, watch_erc_20_input: true, diff --git a/apps/explorer/test/test_helper.exs b/apps/explorer/test/test_helper.exs index 50847130f8..418ea17ea0 100644 --- a/apps/explorer/test/test_helper.exs +++ b/apps/explorer/test/test_helper.exs @@ -12,6 +12,7 @@ ExUnit.start() {:ok, _} = Application.ensure_all_started(:ex_machina) Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, :auto) +Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo.Account, :auto) Mox.defmock(Explorer.ExchangeRates.Source.TestSource, for: Explorer.ExchangeRates.Source) Mox.defmock(Explorer.KnownTokens.Source.TestSource, for: Explorer.KnownTokens.Source) diff --git a/config/runtime/dev.exs b/config/runtime/dev.exs index e7348f1e5d..3c69ee9c1a 100644 --- a/config/runtime/dev.exs +++ b/config/runtime/dev.exs @@ -46,10 +46,11 @@ database_api_url = do: System.get_env("DATABASE_READ_ONLY_API_URL"), else: System.get_env("DATABASE_URL") -pool_size = - if System.get_env("DATABASE_READ_ONLY_API_URL"), - do: String.to_integer(System.get_env("POOL_SIZE", "40")), - else: String.to_integer(System.get_env("POOL_SIZE", "50")) +# pool_size = +# if System.get_env("DATABASE_READ_ONLY_API_URL"), +# do: String.to_integer(System.get_env("POOL_SIZE", "40")), +# else: String.to_integer(System.get_env("POOL_SIZE", "50")) +pool_size = String.to_integer(System.get_env("POOL_SIZE", "30")) # Configure your database config :explorer, Explorer.Repo, @@ -63,7 +64,7 @@ hostname_api = if System.get_env("DATABASE_READ_ONLY_API_URL"), do: nil, else: h pool_size_api = if System.get_env("DATABASE_READ_ONLY_API_URL"), - do: String.to_integer(System.get_env("POOL_SIZE_API", "50")), + do: String.to_integer(System.get_env("POOL_SIZE_API", "10")), else: String.to_integer(System.get_env("POOL_SIZE_API", "10")) # Configure API database @@ -73,6 +74,23 @@ config :explorer, Explorer.Repo.Replica1, url: database_api_url, pool_size: pool_size_api +database_account_url = System.get_env("DATABASE_ACCOUNT_URL") || System.get_env("DATABASE_URL") + +pool_size_account = + if System.get_env("DATABASE_ACCOUNT_URL"), + do: String.to_integer(System.get_env("POOL_SIZE_ACCOUNT", "10")), + else: String.to_integer(System.get_env("POOL_SIZE_ACCOUNT", "10")) + +database_account = if System.get_env("DATABASE_ACCOUNT_URL"), do: nil, else: database +hostname_account = if System.get_env("DATABASE_ACCOUNT_URL"), do: nil, else: hostname + +# Configure Account database +config :explorer, Explorer.Repo.Account, + database: database_account, + hostname: hostname_account, + url: database_account_url, + pool_size: pool_size_account + variant = if is_nil(System.get_env("ETHEREUM_JSONRPC_VARIANT")) do "ganache" diff --git a/config/runtime/prod.exs b/config/runtime/prod.exs index 8a5c8f24cd..43f07fde42 100644 --- a/config/runtime/prod.exs +++ b/config/runtime/prod.exs @@ -49,6 +49,15 @@ config :explorer, Explorer.Repo.Replica1, pool_size: pool_size_api, ssl: String.equivalent?(System.get_env("ECTO_USE_SSL") || "true", "true") +database_account_url = System.get_env("DATABASE_ACCOUNT_URL") +pool_size_account = String.to_integer(System.get_env("POOL_SIZE_ACCOUNT", "50")) + +# Configures Account database +config :explorer, Explorer.Repo.Account, + url: database_account_url, + pool_size: pool_size_account, + ssl: String.equivalent?(System.get_env("ECTO_USE_SSL") || "true", "true") + variant = if is_nil(System.get_env("ETHEREUM_JSONRPC_VARIANT")) do "parity" diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index cd2a3ffdb0..babd98a2f9 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -124,3 +124,6 @@ API_RATE_LIMIT_STATIC_API_KEY= FETCH_REWARDS_WAY=trace_block ENABLE_RUST_VERIFICATION_SERVICE=true RUST_VERIFICATION_SERVICE_URL=http://host.docker.internal:8043/ +# DATABASE_READ_ONLY_API_URL= +# DATABASE_ACCOUNT_URL= +# POOL_SIZE_ACCOUNT= diff --git a/docker/Makefile b/docker/Makefile index 9a5533f1bf..ada9d2dc40 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -502,7 +502,12 @@ endif ifdef RUST_VERIFICATION_SERVICE_URL BLOCKSCOUT_CONTAINER_PARAMS += -e 'RUST_VERIFICATION_SERVICE_URL=$(RUST_VERIFICATION_SERVICE_URL)' endif - +ifdef DATABASE_ACCOUNT_URL + BLOCKSCOUT_CONTAINER_PARAMS += -e 'DATABASE_ACCOUNT_URL=$(DATABASE_ACCOUNT_URL)' +endif +ifdef POOL_SIZE_ACCOUNT + BLOCKSCOUT_CONTAINER_PARAMS += -e 'POOL_SIZE_ACCOUNT=$(POOL_SIZE_ACCOUNT)' +endif HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ") build: