From 6a5916764db12f1397dd36a9e3edef90f26a1138 Mon Sep 17 00:00:00 2001 From: Paul Tsupikoff Date: Sat, 6 Jul 2019 17:14:51 +0300 Subject: [PATCH] Consolidate POSDAO contract reading (#2371) Previously, staking contract reading was arbitrarily spread across Explorer.Staking.ContractState, Explorer.Staking.PoolsReader and Indexer.Fetcher.StakingPools. Using async fetcher infrastructure for staking contracts is inadequate, as blocks may arrive out of order, while we want fetching to be triggered by newer block arrival. Also, contract calls were not batched enough, and it was hard to follow their sequence across involved modules. Now, on each incoming block, which is newer than the last seen, we fully update not only global contract state, but all validators, pools and delegators. All requests are intelligently compiled into four batches. These are defined together to give better overview of performed actions. Chain.import infrastructure is still used for inserting data into DB to leverage smart batching of INSERT queries. Likelihood calculation is added: it zips results of getPoolsToBeElected and getPoolsLikelihood calls to make a map of addresses. Only POS_STAKING_CONTRACT env variable is required now. Other contract addresses are fetched from it during launch. ABIs are concatenated together during launch as well, as we don't support batch requests against distinct ABIs yet. This should be addressed in further PRs. Up-to-date ABIs copied from build artifacts of posdao-contracts repo. File names now correspond to contract names, README directs to their origin. * Fetch inactive delegators, mark pools and delegators deleted (#2205) * Fetch min stakes and token contract address from StakingAuRa (#2313) * Fetch block reward ratio using validatorRewardPercent getter (#2424) * Add missing `banned_until` field in ON CONFLICT clause for staking pools. --- .../lib/ethereum_jsonrpc/encoder.ex | 5 + apps/explorer/config/config.exs | 4 +- apps/explorer/config/test.exs | 2 + apps/explorer/lib/explorer/application.ex | 2 +- .../chain/import/runner/staking_pools.ex | 40 +- .../import/runner/staking_pools_delegators.ex | 29 +- .../lib/explorer/chain/staking_pool.ex | 6 +- .../explorer/chain/staking_pools_delegator.ex | 15 +- .../lib/explorer/staking/contract_reader.ex | 100 ++ .../lib/explorer/staking/contract_state.ex | 205 ++++ .../lib/explorer/staking/epoch_counter.ex | 126 --- .../lib/explorer/staking/pools_reader.ex | 174 ---- .../contracts_abi/posdao/BlockRewardAuRa.json | 632 ++++++++++++ .../priv/contracts_abi/posdao/README.md | 2 + .../staking.json => posdao/StakingAuRa.json} | 911 ++++++++++-------- .../ValidatorSetAuRa.json} | 460 ++++++--- ...0190605125829_delegators_deleted_colum.exs | 10 + ...190718175620_add_block_reward_to_pools.exs | 9 + .../import/runner/staking_pools_test.exs | 12 +- .../explorer/staking/contract_state_test.exs | 208 ++++ .../explorer/staking/epoch_counter_test.exs | 97 -- .../explorer/staking/pools_reader_test.exs | 361 ------- apps/indexer/config/config.exs | 5 +- apps/indexer/lib/indexer/block/fetcher.ex | 5 - .../lib/indexer/block/realtime/fetcher.ex | 4 +- .../lib/indexer/fetcher/staking_pools.ex | 140 --- apps/indexer/lib/indexer/supervisor.ex | 2 - .../indexer/fetcher/staking_pools_test.exs | 224 ----- 28 files changed, 2039 insertions(+), 1751 deletions(-) create mode 100644 apps/explorer/lib/explorer/staking/contract_reader.ex create mode 100644 apps/explorer/lib/explorer/staking/contract_state.ex delete mode 100644 apps/explorer/lib/explorer/staking/epoch_counter.ex delete mode 100644 apps/explorer/lib/explorer/staking/pools_reader.ex create mode 100644 apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json create mode 100644 apps/explorer/priv/contracts_abi/posdao/README.md rename apps/explorer/priv/contracts_abi/{pos/staking.json => posdao/StakingAuRa.json} (90%) rename apps/explorer/priv/contracts_abi/{pos/validators.json => posdao/ValidatorSetAuRa.json} (68%) create mode 100644 apps/explorer/priv/repo/migrations/20190605125829_delegators_deleted_colum.exs create mode 100644 apps/explorer/priv/repo/migrations/20190718175620_add_block_reward_to_pools.exs create mode 100644 apps/explorer/test/explorer/staking/contract_state_test.exs delete mode 100644 apps/explorer/test/explorer/staking/epoch_counter_test.exs delete mode 100644 apps/explorer/test/explorer/staking/pools_reader_test.exs delete mode 100644 apps/indexer/lib/indexer/fetcher/staking_pools.ex delete mode 100644 apps/indexer/test/indexer/fetcher/staking_pools_test.exs diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex index 8cefe10850..f5964bdd0b 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex @@ -66,6 +66,11 @@ defmodule EthereumJSONRPC.Encoder do |> String.slice(2..-1) |> Base.decode16!(case: :lower) |> TypeDecoder.decode_raw(types_list) + |> Enum.zip(types_list) + |> Enum.map(fn + {value, :address} -> "0x" <> Base.encode16(value, case: :lower) + {value, _} -> value + end) {id, {:ok, decoded_data}} rescue diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index f61e4f7289..cc6b5d5a43 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -171,11 +171,11 @@ config :explorer, Explorer.Staking.PoolsReader, staking_contract_address: System.get_env("POS_STAKING_CONTRACT") if System.get_env("POS_STAKING_CONTRACT") do - config :explorer, Explorer.Staking.EpochCounter, + config :explorer, Explorer.Staking.ContractState, enabled: true, staking_contract_address: System.get_env("POS_STAKING_CONTRACT") else - config :explorer, Explorer.Staking.EpochCounter, enabled: false + config :explorer, Explorer.Staking.ContractState, enabled: false end case System.get_env("SUPPLY_MODULE") do diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index bdfdd21b47..281be01cc5 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -32,6 +32,8 @@ config :explorer, Explorer.Market.History.Cataloger, enabled: false config :explorer, Explorer.Tracer, disabled?: false +config :explorer, Explorer.Staking.ContractState, enabled: false + config :logger, :explorer, level: :warn, path: Path.absname("logs/test/explorer.log") diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 4d238df82b..f6d58af84b 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -82,7 +82,7 @@ defmodule Explorer.Application do configure(Explorer.Counters.AverageBlockTime), configure(Explorer.Counters.Bridge), configure(Explorer.Validator.MetadataProcessor), - configure(Explorer.Staking.EpochCounter) + configure(Explorer.Staking.ContractState) ] |> List.flatten() end diff --git a/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex b/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex index 3568b0da6e..030f240d8d 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/staking_pools.ex @@ -51,9 +51,6 @@ defmodule Explorer.Chain.Import.Runner.StakingPools do |> Multi.run(:insert_staking_pools, fn repo, _ -> insert(repo, changes_list, insert_options) end) - |> Multi.run(:calculate_stakes_ratio, fn repo, _ -> - calculate_stakes_ratio(repo, insert_options) - end) end @impl Import.Runner @@ -131,51 +128,18 @@ defmodule Explorer.Chain.Import.Runner.StakingPools do is_banned: fragment("EXCLUDED.is_banned"), is_validator: fragment("EXCLUDED.is_validator"), likelihood: fragment("EXCLUDED.likelihood"), + block_reward_ratio: fragment("EXCLUDED.block_reward_ratio"), staked_ratio: fragment("EXCLUDED.staked_ratio"), self_staked_amount: fragment("EXCLUDED.self_staked_amount"), staked_amount: fragment("EXCLUDED.staked_amount"), was_banned_count: fragment("EXCLUDED.was_banned_count"), was_validator_count: fragment("EXCLUDED.was_validator_count"), is_deleted: fragment("EXCLUDED.is_deleted"), + banned_until: fragment("EXCLUDED.banned_until"), inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", pool.inserted_at), updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", pool.updated_at) ] ] ) end - - defp calculate_stakes_ratio(repo, %{timeout: timeout}) do - total_query = - from( - pool in StakingPool, - where: pool.is_active == true, - select: sum(pool.staked_amount) - ) - - total = repo.one!(total_query) - - if total.value > Decimal.new(0) do - update_query = - from( - p in StakingPool, - where: p.is_active == true, - # ShareLocks order already enforced by `acquire_all_staking_pools` (see docs: sharelocks.md) - update: [ - set: [ - staked_ratio: p.staked_amount / ^total.value * 100, - likelihood: p.staked_amount / ^total.value * 100 - ] - ] - ) - - {count, _} = repo.update_all(update_query, [], timeout: timeout) - - {:ok, count} - else - {:ok, 1} - end - rescue - postgrex_error in Postgrex.Error -> - {:error, %{exception: postgrex_error}} - end end diff --git a/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex b/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex index 4677aeee04..07e854f846 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/staking_pools_delegators.ex @@ -41,6 +41,9 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsDelegators do |> Map.put(:timestamps, timestamps) multi + |> Multi.run(:delete_delegators, fn repo, _ -> + mark_as_deleted(repo, insert_options) + end) |> Multi.run(:insert_staking_pools_delegators, fn repo, _ -> insert(repo, changes_list, insert_options) end) @@ -49,6 +52,28 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsDelegators do @impl Import.Runner def timeout, do: @timeout + defp mark_as_deleted(repo, %{timeout: timeout}) do + query = + from( + d in StakingPoolsDelegator, + update: [ + set: [ + is_active: false, + is_deleted: true + ] + ] + ) + + try do + {_, result} = repo.update_all(query, [], timeout: timeout) + + {:ok, result} + rescue + postgrex_error in Postgrex.Error -> + {:error, %{exception: postgrex_error}} + end + end + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, @@ -86,7 +111,9 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsDelegators do max_ordered_withdraw_allowed: fragment("EXCLUDED.max_ordered_withdraw_allowed"), ordered_withdraw_epoch: fragment("EXCLUDED.ordered_withdraw_epoch"), inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", delegator.inserted_at), - updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", delegator.updated_at) + updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", delegator.updated_at), + is_active: fragment("EXCLUDED.is_active"), + is_deleted: fragment("EXCLUDED.is_deleted") ] ] ) diff --git a/apps/explorer/lib/explorer/chain/staking_pool.ex b/apps/explorer/lib/explorer/chain/staking_pool.ex index 7949661c23..9d5b0e8e43 100644 --- a/apps/explorer/lib/explorer/chain/staking_pool.ex +++ b/apps/explorer/lib/explorer/chain/staking_pool.ex @@ -21,7 +21,8 @@ defmodule Explorer.Chain.StakingPool do is_active: boolean, is_banned: boolean, is_validator: boolean, - likelihood: integer, + likelihood: Decimal.t(), + block_reward_ratio: Decimal.t(), staked_ratio: Decimal.t(), self_staked_amount: Wei.t(), staked_amount: Wei.t(), @@ -33,7 +34,7 @@ defmodule Explorer.Chain.StakingPool do @attrs ~w( is_active delegators_count staked_amount self_staked_amount is_validator was_validator_count is_banned was_banned_count banned_until likelihood - staked_ratio staking_address_hash mining_address_hash + staked_ratio staking_address_hash mining_address_hash block_reward_ratio )a @req_attrs ~w( is_active delegators_count staked_amount self_staked_amount is_validator @@ -48,6 +49,7 @@ defmodule Explorer.Chain.StakingPool do field(:is_banned, :boolean, default: false) field(:is_validator, :boolean, default: false) field(:likelihood, :decimal) + field(:block_reward_ratio, :decimal) field(:staked_ratio, :decimal) field(:self_staked_amount, Wei) field(:staked_amount, Wei) diff --git a/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex b/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex index 8fabc6c447..2a6536bf1f 100644 --- a/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex +++ b/apps/explorer/lib/explorer/chain/staking_pools_delegator.ex @@ -20,12 +20,21 @@ defmodule Explorer.Chain.StakingPoolsDelegator do max_withdraw_allowed: Wei.t(), ordered_withdraw: Wei.t(), stake_amount: Wei.t(), - ordered_withdraw_epoch: integer() + ordered_withdraw_epoch: integer(), + is_active: boolean(), + is_deleted: boolean() } @attrs ~w( pool_address_hash delegator_address_hash max_ordered_withdraw_allowed max_withdraw_allowed ordered_withdraw stake_amount ordered_withdraw_epoch + is_active is_deleted + )a + + @req_attrs ~w( + pool_address_hash delegator_address_hash max_ordered_withdraw_allowed + max_withdraw_allowed ordered_withdraw stake_amount ordered_withdraw_epoch + )a schema "staking_pools_delegators" do @@ -34,6 +43,8 @@ defmodule Explorer.Chain.StakingPoolsDelegator do field(:ordered_withdraw, Wei) field(:ordered_withdraw_epoch, :integer) field(:stake_amount, Wei) + field(:is_active, :boolean, default: true) + field(:is_deleted, :boolean, default: false) belongs_to( :staking_pool, @@ -58,7 +69,7 @@ defmodule Explorer.Chain.StakingPoolsDelegator do def changeset(staking_pools_delegator, attrs) do staking_pools_delegator |> cast(attrs, @attrs) - |> validate_required(@attrs) + |> validate_required(@req_attrs) |> unique_constraint(:pool_address_hash, name: :pools_delegator_index) end end diff --git a/apps/explorer/lib/explorer/staking/contract_reader.ex b/apps/explorer/lib/explorer/staking/contract_reader.ex new file mode 100644 index 0000000000..a928eb9b6c --- /dev/null +++ b/apps/explorer/lib/explorer/staking/contract_reader.ex @@ -0,0 +1,100 @@ +defmodule Explorer.Staking.ContractReader do + @moduledoc """ + Routines for batched fetching of information from POSDAO contracts + """ + + alias Explorer.SmartContract.Reader + + def global_requests do + [ + token_contract_address: {:staking, "erc20TokenContract", []}, + min_candidate_stake: {:staking, "candidateMinStake", []}, + min_delegator_stake: {:staking, "delegatorMinStake", []}, + epoch_number: {:staking, "stakingEpoch", []}, + epoch_end_block: {:staking, "stakingEpochEndBlock", []}, + active_pools: {:staking, "getPools", []}, + inactive_pools: {:staking, "getPoolsInactive", []}, + pools_likely: {:staking, "getPoolsToBeElected", []}, + pools_likelihood: {:staking, "getPoolsLikelihood", []}, + validators: {:validator_set, "getValidators", []} + ] + end + + def pool_staking_requests(staking_address) do + [ + mining_address_hash: {:validator_set, "miningByStakingAddress", [staking_address]}, + is_active: {:staking, "isPoolActive", [staking_address]}, + active_delegators: {:staking, "poolDelegators", [staking_address]}, + inactive_delegators: {:staking, "poolDelegatorsInactive", [staking_address]}, + staked_amount: {:staking, "stakeAmountTotalMinusOrderedWithdraw", [staking_address]}, + self_staked_amount: {:staking, "stakeAmountMinusOrderedWithdraw", [staking_address, staking_address]}, + block_reward: {:block_reward, "validatorRewardPercent", [staking_address]} + ] + end + + def pool_mining_requests(mining_address) do + [ + is_validator: {:validator_set, "isValidator", [mining_address]}, + was_validator_count: {:validator_set, "validatorCounter", [mining_address]}, + is_banned: {:validator_set, "isValidatorBanned", [mining_address]}, + banned_until: {:validator_set, "bannedUntil", [mining_address]}, + was_banned_count: {:validator_set, "banCounter", [mining_address]} + ] + end + + def delegator_requests(pool_address, delegator_address) do + [ + stake_amount: {:staking, "stakeAmount", [pool_address, delegator_address]}, + ordered_withdraw: {:staking, "orderedWithdrawAmount", [pool_address, delegator_address]}, + max_withdraw_allowed: {:staking, "maxWithdrawAllowed", [pool_address, delegator_address]}, + max_ordered_withdraw_allowed: {:staking, "maxWithdrawOrderAllowed", [pool_address, delegator_address]}, + ordered_withdraw_epoch: {:staking, "orderWithdrawEpoch", [pool_address, delegator_address]} + ] + end + + def perform_requests(requests, contracts, abi) do + requests + |> generate_requests(contracts) + |> Reader.query_contracts(abi) + |> parse_responses(requests) + end + + def perform_grouped_requests(requests, keys, contracts, abi) do + requests + |> List.flatten() + |> generate_requests(contracts) + |> Reader.query_contracts(abi) + |> parse_grouped_responses(keys, requests) + end + + defp generate_requests(functions, contracts) do + Enum.map(functions, fn {_, {contract, function, args}} -> + %{ + contract_address: contracts[contract], + function_name: function, + args: args + } + end) + end + + defp parse_responses(responses, requests) do + requests + |> Enum.zip(responses) + |> Enum.into(%{}, fn {{key, _}, {:ok, response}} -> + case response do + [item] -> {key, item} + items -> {key, items} + end + end) + end + + defp parse_grouped_responses(responses, keys, grouped_requests) do + {grouped_responses, _} = Enum.map_reduce(grouped_requests, responses, &Enum.split(&2, length(&1))) + + [keys, grouped_requests, grouped_responses] + |> Enum.zip() + |> Enum.into(%{}, fn {key, requests, responses} -> + {key, parse_responses(responses, requests)} + end) + end +end diff --git a/apps/explorer/lib/explorer/staking/contract_state.ex b/apps/explorer/lib/explorer/staking/contract_state.ex new file mode 100644 index 0000000000..656a91e249 --- /dev/null +++ b/apps/explorer/lib/explorer/staking/contract_state.ex @@ -0,0 +1,205 @@ +defmodule Explorer.Staking.ContractState do + @moduledoc """ + Fetches all information from POSDAO staking contracts. + All contract calls are batched into four requests, according to their dependencies. + Subscribes to new block notifications and refreshes when previously unseen block arrives. + """ + + use GenServer + + alias Explorer.Chain + alias Explorer.Chain.Events.Subscriber + alias Explorer.SmartContract.Reader + alias Explorer.Staking.ContractReader + + @table_name __MODULE__ + @table_keys [ + :token_contract_address, + :min_candidate_stake, + :min_delegator_stake, + :epoch_number, + :epoch_end_block + ] + + defstruct [ + :seen_block, + :contracts, + :abi + ] + + @spec get(atom(), value) :: value when value: any() + def get(key, default \\ nil) when key in @table_keys do + with info when info != :undefined <- :ets.info(@table_name), + [{_, value}] <- :ets.lookup(@table_name, key) do + value + else + _ -> default + end + end + + def start_link([]) do + GenServer.start_link(__MODULE__, [], name: __MODULE__) + end + + def init([]) do + :ets.new(@table_name, [ + :set, + :named_table, + :public, + read_concurrency: true, + write_concurrency: true + ]) + + Subscriber.to(:blocks, :realtime) + + staking_abi = abi("StakingAuRa") + validator_set_abi = abi("ValidatorSetAuRa") + block_reward_abi = abi("BlockRewardAuRa") + + staking_contract_address = Application.get_env(:explorer, __MODULE__)[:staking_contract_address] + + %{"validatorSetContract" => {:ok, [validator_set_contract_address]}} = + Reader.query_contract(staking_contract_address, staking_abi, %{"validatorSetContract" => []}) + + %{"blockRewardContract" => {:ok, [block_reward_contract_address]}} = + Reader.query_contract(validator_set_contract_address, validator_set_abi, %{"blockRewardContract" => []}) + + state = %__MODULE__{ + seen_block: 0, + contracts: %{ + staking: staking_contract_address, + validator_set: validator_set_contract_address, + block_reward: block_reward_contract_address + }, + abi: staking_abi ++ validator_set_abi ++ block_reward_abi + } + + {:ok, state, {:continue, []}} + end + + def handle_continue(_, state) do + fetch_state(state.contracts, state.abi) + {:noreply, state} + end + + @doc "Handles new blocks and decides to fetch fresh chain info" + def handle_info({:chain_event, :blocks, :realtime, blocks}, state) do + latest_block = Enum.max_by(blocks, & &1.number) + + if latest_block.number > state.seen_block do + fetch_state(state.contracts, state.abi) + {:noreply, %{state | seen_block: latest_block.number}} + else + {:noreply, state} + end + end + + defp fetch_state(contracts, abi) do + global_responses = ContractReader.perform_requests(ContractReader.global_requests(), contracts, abi) + + settings = + global_responses + |> Map.take([ + :token_contract_address, + :min_candidate_stake, + :min_delegator_stake, + :epoch_number, + :epoch_end_block + ]) + |> Map.to_list() + + :ets.insert(@table_name, settings) + + pools = global_responses.active_pools ++ global_responses.inactive_pools + + pool_staking_responses = + pools + |> Enum.map(&ContractReader.pool_staking_requests/1) + |> ContractReader.perform_grouped_requests(pools, contracts, abi) + + pool_mining_responses = + pools + |> Enum.map(&ContractReader.pool_mining_requests(pool_staking_responses[&1].mining_address_hash)) + |> ContractReader.perform_grouped_requests(pools, contracts, abi) + + delegators = + Enum.flat_map(pool_staking_responses, fn {pool_address, responses} -> + Enum.map(responses.active_delegators, &{pool_address, &1, true}) ++ + Enum.map(responses.inactive_delegators, &{pool_address, &1, false}) + end) + + delegator_responses = + delegators + |> Enum.map(fn {pool_address, delegator_address, _} -> + ContractReader.delegator_requests(pool_address, delegator_address) + end) + |> ContractReader.perform_grouped_requests(delegators, contracts, abi) + + staked_total = Enum.sum(for {_, pool} <- pool_staking_responses, pool.is_active, do: pool.staked_amount) + [likelihood_values, total_likelihood] = global_responses.pools_likelihood + + likelihood = + global_responses.pools_likely + |> Enum.zip(likelihood_values) + |> Enum.into(%{}) + + pool_entries = + Enum.map(pools, fn staking_address -> + staking_response = pool_staking_responses[staking_address] + mining_response = pool_mining_responses[staking_address] + + %{ + staking_address_hash: staking_address, + delegators_count: length(staking_response.active_delegators), + staked_ratio: ratio(staking_response.staked_amount, staked_total), + likelihood: ratio(likelihood[staking_address] || 0, total_likelihood), + block_reward_ratio: staking_response.block_reward / 10_000, + is_deleted: false + } + |> Map.merge( + Map.take(staking_response, [ + :mining_address_hash, + :is_active, + :staked_amount, + :self_staked_amount + ]) + ) + |> Map.merge( + Map.take(mining_response, [ + :is_validator, + :was_validator_count, + :is_banned, + :banned_until, + :was_banned_count + ]) + ) + end) + + delegator_entries = + Enum.map(delegator_responses, fn {{pool_address, delegator_address, is_active}, response} -> + Map.merge(response, %{ + delegator_address_hash: delegator_address, + pool_address_hash: pool_address, + is_active: is_active + }) + end) + + {:ok, _} = + Chain.import(%{ + staking_pools: %{params: pool_entries}, + staking_pools_delegators: %{params: delegator_entries}, + timeout: :infinity + }) + end + + defp ratio(_numerator, 0), do: 0 + defp ratio(numerator, denominator), do: numerator / denominator * 100 + + # sobelow_skip ["Traversal"] + defp abi(file_name) do + :explorer + |> Application.app_dir("priv/contracts_abi/posdao/#{file_name}.json") + |> File.read!() + |> Jason.decode!() + end +end diff --git a/apps/explorer/lib/explorer/staking/epoch_counter.ex b/apps/explorer/lib/explorer/staking/epoch_counter.ex deleted file mode 100644 index 70cefe3ad3..0000000000 --- a/apps/explorer/lib/explorer/staking/epoch_counter.ex +++ /dev/null @@ -1,126 +0,0 @@ -defmodule Explorer.Staking.EpochCounter do - @moduledoc """ - Fetches current staking epoch number and the epoch end block number. - It subscribes to handle new blocks and conclude whether the epoch is over. - """ - - use GenServer - - alias Explorer.Chain.Events.Subscriber - alias Explorer.SmartContract.Reader - - @table_name __MODULE__ - @epoch_key "epoch_num" - @epoch_end_key "epoch_end_block" - - @doc "Current staking epoch number" - def epoch_number do - if :ets.info(@table_name) != :undefined do - case :ets.lookup(@table_name, @epoch_key) do - [{_, epoch_num}] -> - epoch_num - - _ -> - 0 - end - end - end - - @doc "Block number on which will start new epoch" - def epoch_end_block do - if :ets.info(@table_name) != :undefined do - case :ets.lookup(@table_name, @epoch_end_key) do - [{_, epoch_end}] -> - epoch_end - - _ -> - 0 - end - end - end - - def start_link([]) do - GenServer.start_link(__MODULE__, [], name: __MODULE__) - end - - def init([]) do - :ets.new(@table_name, [ - :set, - :named_table, - :public, - write_concurrency: true - ]) - - Subscriber.to(:blocks, :realtime) - {:ok, [], {:continue, :epoch_info}} - end - - def handle_continue(:epoch_info, state) do - fetch_epoch_info() - {:noreply, state} - end - - @doc "Handles new blocks and decides to fetch new epoch info" - def handle_info({:chain_event, :blocks, :realtime, blocks}, state) do - new_block_number = - blocks - |> Enum.map(&Map.get(&1, :number, 0)) - |> Enum.max(fn -> 0 end) - - case :ets.lookup(@table_name, @epoch_end_key) do - [] -> - fetch_epoch_info() - - [{_, epoch_end_block}] when epoch_end_block < new_block_number -> - fetch_epoch_info() - - _ -> - :ok - end - - {:noreply, state} - end - - defp fetch_epoch_info do - # 794c0c68 = keccak256(stakingEpoch()) - # 8c2243ae = keccak256(stakingEpochEndBlock()) - with data <- get_epoch_info(), - {:ok, [epoch_num]} <- data["794c0c68"], - {:ok, [epoch_end_block]} <- data["8c2243ae"] do - :ets.insert(@table_name, {@epoch_key, epoch_num}) - :ets.insert(@table_name, {@epoch_end_key, epoch_end_block}) - end - end - - defp get_epoch_info do - contract_abi = abi("staking.json") - - method_ids = ["794c0c68", "8c2243ae"] - - method_ids - |> Enum.map(fn method_id -> - %{ - contract_address: staking_address(), - method_id: method_id, - args: [] - } - end) - |> Reader.query_contracts(contract_abi) - |> Enum.zip(method_ids) - |> Enum.into(%{}, fn {response, method_id} -> - {method_id, response} - end) - end - - defp staking_address do - Application.get_env(:explorer, __MODULE__, [])[:staking_contract_address] - end - - # sobelow_skip ["Traversal"] - defp abi(file_name) do - :explorer - |> Application.app_dir("priv/contracts_abi/pos/#{file_name}") - |> File.read!() - |> Jason.decode!() - end -end diff --git a/apps/explorer/lib/explorer/staking/pools_reader.ex b/apps/explorer/lib/explorer/staking/pools_reader.ex deleted file mode 100644 index 16f59acffd..0000000000 --- a/apps/explorer/lib/explorer/staking/pools_reader.ex +++ /dev/null @@ -1,174 +0,0 @@ -defmodule Explorer.Staking.PoolsReader do - @moduledoc """ - Reads staking pools using Smart Contract functions from the blockchain. - """ - alias Explorer.SmartContract.Reader - - @spec get_pools() :: [String.t()] - def get_pools do - get_active_pools() ++ get_inactive_pools() - end - - @spec get_active_pools() :: [String.t()] - def get_active_pools do - # 673a2a1f = keccak256(getPools()) - {:ok, [active_pools]} = call_staking_method("673a2a1f", []) - active_pools - end - - @spec get_inactive_pools() :: [String.t()] - def get_inactive_pools do - # df6f55f5 = keccak256(getPoolsInactive()) - {:ok, [inactive_pools]} = call_staking_method("df6f55f5", []) - inactive_pools - end - - @spec pool_data(String.t()) :: {:ok, map()} | :error - def pool_data(staking_address) do - # 00535175 = keccak256(miningByStakingAddress(address)) - with {:ok, [mining_address]} <- call_validators_method("00535175", [staking_address]), - data = fetch_pool_data(staking_address, mining_address), - {:ok, [is_active]} <- data["a711e6a1"], - {:ok, [delegator_addresses]} <- data["9ea8082b"], - delegators_count = Enum.count(delegator_addresses), - delegators = delegators_data(delegator_addresses, staking_address), - {:ok, [staked_amount]} <- data["234fbf2b"], - {:ok, [self_staked_amount]} <- data["58daab6a"], - {:ok, [is_validator]} <- data["facd743b"], - {:ok, [was_validator_count]} <- data["b41832e4"], - {:ok, [is_banned]} <- data["a92252ae"], - {:ok, [banned_until]} <- data["5836d08a"], - {:ok, [was_banned_count]} <- data["1d0cd4c6"] do - { - :ok, - %{ - staking_address_hash: staking_address, - mining_address_hash: mining_address, - is_active: is_active, - delegators_count: delegators_count, - staked_amount: staked_amount, - self_staked_amount: self_staked_amount, - is_validator: is_validator, - was_validator_count: was_validator_count, - is_banned: is_banned, - banned_until: banned_until, - was_banned_count: was_banned_count, - delegators: delegators - } - } - else - _ -> - :error - end - end - - defp delegators_data(delegators, pool_address) do - Enum.map(delegators, fn address -> - # a697ecff = keccak256(stakeAmount(address,address)) - # e9ab0300 = keccak256(orderedWithdrawAmount(address,address)) - # 6bda1577 = keccak256(maxWithdrawAllowed(address,address)) - # 950a6513 = keccak256(maxWithdrawOrderAllowed(address,address)) - # a4205967 = keccak256(orderWithdrawEpoch(address,address)) - data = - call_methods([ - {:staking, "a697ecff", [pool_address, address]}, - {:staking, "e9ab0300", [pool_address, address]}, - {:staking, "6bda1577", [pool_address, address]}, - {:staking, "950a6513", [pool_address, address]}, - {:staking, "a4205967", [pool_address, address]} - ]) - - {:ok, [stake_amount]} = data["a697ecff"] - {:ok, [ordered_withdraw]} = data["e9ab0300"] - {:ok, [max_withdraw_allowed]} = data["6bda1577"] - {:ok, [max_ordered_withdraw_allowed]} = data["950a6513"] - {:ok, [ordered_withdraw_epoch]} = data["a4205967"] - - %{ - delegator_address_hash: address, - pool_address_hash: pool_address, - stake_amount: stake_amount, - ordered_withdraw: ordered_withdraw, - max_withdraw_allowed: max_withdraw_allowed, - max_ordered_withdraw_allowed: max_ordered_withdraw_allowed, - ordered_withdraw_epoch: ordered_withdraw_epoch - } - end) - end - - defp call_staking_method(method, params) do - %{^method => resp} = - Reader.query_contract(config(:staking_contract_address), abi("staking.json"), %{ - method => params - }) - - resp - end - - defp call_validators_method(method, params) do - %{^method => resp} = - Reader.query_contract(config(:validators_contract_address), abi("validators.json"), %{ - method => params - }) - - resp - end - - defp fetch_pool_data(staking_address, mining_address) do - # a711e6a1 = keccak256(isPoolActive(address)) - # 9ea8082b = keccak256(poolDelegators(address)) - # 234fbf2b = keccak256(stakeAmountTotalMinusOrderedWithdraw(address)) - # 58daab6a = keccak256(stakeAmountMinusOrderedWithdraw(address,address)) - # facd743b = keccak256(isValidator(address)) - # b41832e4 = keccak256(validatorCounter(address)) - # a92252ae = keccak256(isValidatorBanned(address)) - # 5836d08a = keccak256(bannedUntil(address)) - # 1d0cd4c6 = keccak256(banCounter(address)) - call_methods([ - {:staking, "a711e6a1", [staking_address]}, - {:staking, "9ea8082b", [staking_address]}, - {:staking, "234fbf2b", [staking_address]}, - {:staking, "58daab6a", [staking_address, staking_address]}, - {:validators, "facd743b", [mining_address]}, - {:validators, "b41832e4", [mining_address]}, - {:validators, "a92252ae", [mining_address]}, - {:validators, "5836d08a", [mining_address]}, - {:validators, "1d0cd4c6", [mining_address]} - ]) - end - - defp call_methods(methods) do - contract_abi = abi("staking.json") ++ abi("validators.json") - - methods - |> Enum.map(&format_request/1) - |> Reader.query_contracts(contract_abi) - |> Enum.zip(methods) - |> Enum.into(%{}, fn {response, {_, method_id, _}} -> - {method_id, response} - end) - end - - defp format_request({contract_name, method_id, params}) do - %{ - contract_address: contract(contract_name), - method_id: method_id, - args: params - } - end - - defp contract(:staking), do: config(:staking_contract_address) - defp contract(:validators), do: config(:validators_contract_address) - - defp config(key) do - Application.get_env(:explorer, __MODULE__, [])[key] - end - - # sobelow_skip ["Traversal"] - defp abi(file_name) do - :explorer - |> Application.app_dir("priv/contracts_abi/pos/#{file_name}") - |> File.read!() - |> Jason.decode!() - end -end diff --git a/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json b/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json new file mode 100644 index 0000000000..f4d0ad316b --- /dev/null +++ b/apps/explorer/priv/contracts_abi/posdao/BlockRewardAuRa.json @@ -0,0 +1,632 @@ +[ + { + "constant": true, + "inputs": [], + "name": "DELEGATORS_ALIQUOT", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "bridgeTokenFee", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isRewarding", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "mintedForAccountInBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "epochPoolNativeReward", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "mintedForAccount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "mintedInBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "mintedTotally", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "tokenRewardUndistributed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nativeRewardUndistributed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isSnapshotting", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "mintedTotallyByBridge", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "epochPoolTokenReward", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "validatorSetContract", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "bridgeNativeFee", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "snapshotTotalStakeAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "blocksCreated", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "name": "bridge", + "type": "address" + } + ], + "name": "AddedReceiver", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "receivers", + "type": "address[]" + }, + { + "indexed": false, + "name": "rewards", + "type": "uint256[]" + } + ], + "name": "MintedNative", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "addBridgeNativeFeeReceivers", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "addBridgeTokenFeeReceivers", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + }, + { + "name": "_receiver", + "type": "address" + } + ], + "name": "addExtraReceiver", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_validatorSet", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_bridge", + "type": "address" + }, + { + "name": "_prevBlockRewardContract", + "type": "address" + } + ], + "name": "migrateMintingStatistics", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "benefactors", + "type": "address[]" + }, + { + "name": "kind", + "type": "uint16[]" + } + ], + "name": "reward", + "outputs": [ + { + "name": "receiversNative", + "type": "address[]" + }, + { + "name": "rewardsNative", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_bridgesAllowed", + "type": "address[]" + } + ], + "name": "setErcToNativeBridgesAllowed", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_bridgesAllowed", + "type": "address[]" + } + ], + "name": "setNativeToErcBridgesAllowed", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_bridgesAllowed", + "type": "address[]" + } + ], + "name": "setErcToErcBridgesAllowed", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "blockRewardContractId", + "outputs": [ + { + "name": "", + "type": "bytes4" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ercToErcBridgesAllowed", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ercToNativeBridgesAllowed", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "extraReceiversQueueSize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nativeToErcBridgesAllowed", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_validatorStakingAddress", + "type": "address" + } + ], + "name": "snapshotRewardPercents", + "outputs": [ + { + "name": "result", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_validatorStakingAddress", + "type": "address" + } + ], + "name": "snapshotStakers", + "outputs": [ + { + "name": "result", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "snapshotStakingAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_stakingAddress", + "type": "address" + } + ], + "name": "validatorRewardPercent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/apps/explorer/priv/contracts_abi/posdao/README.md b/apps/explorer/priv/contracts_abi/posdao/README.md new file mode 100644 index 0000000000..5920a12993 --- /dev/null +++ b/apps/explorer/priv/contracts_abi/posdao/README.md @@ -0,0 +1,2 @@ +ABIs are taken from compiled contract JSONs in the `build/` directory of https://github.com/poanetwork/posdao-contracts. +Docs: https://poanetwork.github.io/posdao-contracts/docs/ diff --git a/apps/explorer/priv/contracts_abi/pos/staking.json b/apps/explorer/priv/contracts_abi/posdao/StakingAuRa.json similarity index 90% rename from apps/explorer/priv/contracts_abi/pos/staking.json rename to apps/explorer/priv/contracts_abi/posdao/StakingAuRa.json index 33f773ea61..77fc815d21 100644 --- a/apps/explorer/priv/contracts_abi/pos/staking.json +++ b/apps/explorer/priv/contracts_abi/posdao/StakingAuRa.json @@ -3,11 +3,11 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", + "name": "", "type": "address" }, { - "name": "_delegator", + "name": "", "type": "address" } ], @@ -26,11 +26,11 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", + "name": "", "type": "address" } ], - "name": "stakeAmountTotalMinusOrderedWithdraw", + "name": "stakeAmountTotal", "outputs": [ { "name": "", @@ -42,101 +42,56 @@ "type": "function" }, { - "constant": false, - "inputs": [ + "constant": true, + "inputs": [], + "name": "candidateMinStake", + "outputs": [ { - "name": "_erc20TokenContract", - "type": "address" + "name": "", + "type": "uint256" } ], - "name": "setErc20TokenContract", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { - "name": "_fromPoolStakingAddress", - "type": "address" - }, - { - "name": "_toPoolStakingAddress", + "name": "", "type": "address" - }, - { - "name": "_amount", - "type": "uint256" } ], - "name": "moveStake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ + "name": "poolInactiveIndex", + "outputs": [ { - "name": "_minStake", + "name": "", "type": "uint256" } ], - "name": "setDelegatorMinStake", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_stakingAddress", - "type": "address" - } - ], - "name": "removePool", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [], - "name": "removePool", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ + "name": "stakingEpochStartBlock", + "outputs": [ { - "name": "_minStake", + "name": "", "type": "uint256" } ], - "name": "setCandidateMinStake", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "constant": true, - "inputs": [ - { - "name": "_poolStakingAddress", - "type": "address" - } - ], - "name": "stakeAmountTotal", + "inputs": [], + "name": "stakingEpoch", "outputs": [ { "name": "", @@ -149,21 +104,12 @@ }, { "constant": true, - "inputs": [ - { - "name": "_poolStakingAddress", - "type": "address" - }, - { - "name": "_staker", - "type": "address" - } - ], - "name": "stakeAmountMinusOrderedWithdraw", + "inputs": [], + "name": "erc20TokenContract", "outputs": [ { "name": "", - "type": "uint256" + "type": "address" } ], "payable": false, @@ -174,11 +120,15 @@ "constant": true, "inputs": [ { - "name": "_stakingAddress", + "name": "", + "type": "address" + }, + { + "name": "", "type": "address" } ], - "name": "poolInactiveIndex", + "name": "poolDelegatorInactiveIndex", "outputs": [ { "name": "", @@ -192,11 +142,11 @@ { "constant": true, "inputs": [], - "name": "getPools", + "name": "stakeWithdrawDisallowPeriod", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -207,15 +157,15 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", + "name": "", "type": "address" }, { - "name": "_staker", + "name": "", "type": "address" } ], - "name": "maxWithdrawAllowed", + "name": "orderWithdrawEpoch", "outputs": [ { "name": "", @@ -230,15 +180,15 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", + "name": "", "type": "address" }, { - "name": "_staker", + "name": "", "type": "address" } ], - "name": "stakeAmountByCurrentEpoch", + "name": "stakeAmount", "outputs": [ { "name": "", @@ -251,8 +201,13 @@ }, { "constant": true, - "inputs": [], - "name": "stakingEpoch", + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "poolIndex", "outputs": [ { "name": "", @@ -266,7 +221,7 @@ { "constant": true, "inputs": [], - "name": "getDelegatorMinStake", + "name": "STAKE_UNIT", "outputs": [ { "name": "", @@ -280,11 +235,11 @@ { "constant": true, "inputs": [], - "name": "erc20TokenContract", + "name": "erc20Restricted", "outputs": [ { "name": "", - "type": "address" + "type": "bool" } ], "payable": false, @@ -294,7 +249,7 @@ { "constant": true, "inputs": [], - "name": "getCandidateMinStake", + "name": "stakingEpochDuration", "outputs": [ { "name": "", @@ -307,17 +262,8 @@ }, { "constant": true, - "inputs": [ - { - "name": "_poolStakingAddress", - "type": "address" - }, - { - "name": "_staker", - "type": "address" - } - ], - "name": "maxWithdrawOrderAllowed", + "inputs": [], + "name": "delegatorMinStake", "outputs": [ { "name": "", @@ -332,15 +278,11 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", - "type": "address" - }, - { - "name": "_delegator", + "name": "", "type": "address" } ], - "name": "poolDelegatorInactiveIndex", + "name": "orderedWithdrawAmountTotal", "outputs": [ { "name": "", @@ -354,15 +296,11 @@ { "constant": true, "inputs": [], - "name": "getPoolsLikelihood", + "name": "validatorSetContract", "outputs": [ { - "name": "likelihoods", - "type": "int256[]" - }, - { - "name": "sum", - "type": "int256" + "name": "", + "type": "address" } ], "payable": false, @@ -370,32 +308,22 @@ "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { - "name": "_unremovableStakingAddress", + "name": "", "type": "address" - } - ], - "name": "clearUnremovableValidator", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ + }, { - "name": "_poolStakingAddress", + "name": "", "type": "address" } ], - "name": "poolDelegators", + "name": "orderedWithdrawAmount", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -404,17 +332,8 @@ }, { "constant": true, - "inputs": [ - { - "name": "_poolStakingAddress", - "type": "address" - }, - { - "name": "_staker", - "type": "address" - } - ], - "name": "orderWithdrawEpoch", + "inputs": [], + "name": "MAX_DELEGATORS_PER_POOL", "outputs": [ { "name": "", @@ -431,35 +350,27 @@ { "name": "", "type": "address" - }, - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "bytes" } ], - "name": "onTokenTransfer", + "name": "poolToBeRemovedIndex", "outputs": [ { "name": "", - "type": "bool" + "type": "uint256" } ], "payable": false, - "stateMutability": "pure", + "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], - "name": "getPoolsToBeElected", + "name": "MAX_CANDIDATES", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -470,15 +381,11 @@ "constant": true, "inputs": [ { - "name": "_poolStakingAddress", - "type": "address" - }, - { - "name": "_staker", + "name": "", "type": "address" } ], - "name": "stakeAmount", + "name": "poolToBeElectedIndex", "outputs": [ { "name": "", @@ -490,144 +397,429 @@ "type": "function" }, { - "constant": true, + "anonymous": false, "inputs": [ { - "name": "_stakingAddress", + "indexed": true, + "name": "fromPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "staker", "type": "address" + }, + { + "indexed": true, + "name": "stakingEpoch", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" } ], - "name": "isPoolActive", - "outputs": [ - { - "name": "", - "type": "bool" + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "toPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "staker", + "type": "address" + }, + { + "indexed": true, + "name": "stakingEpoch", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" } ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "fromPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "toPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "staker", + "type": "address" + }, + { + "indexed": true, + "name": "stakingEpoch", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "StakeMoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "fromPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "staker", + "type": "address" + }, + { + "indexed": true, + "name": "stakingEpoch", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "int256" + } + ], + "name": "WithdrawalOrdered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "fromPoolStakingAddress", + "type": "address" + }, + { + "indexed": true, + "name": "staker", + "type": "address" + }, + { + "indexed": true, + "name": "stakingEpoch", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + }, + { + "name": "_miningAddress", + "type": "address" + } + ], + "name": "addPool", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { - "name": "_toPoolStakingAddress", + "name": "_miningAddress", + "type": "address" + } + ], + "name": "addPoolNative", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_unremovableStakingAddress", + "type": "address" + } + ], + "name": "clearUnremovableValidator", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "incrementStakingEpoch", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_validatorSetContract", "type": "address" }, { - "name": "_amount", + "name": "_initialStakingAddresses", + "type": "address[]" + }, + { + "name": "_delegatorMinStake", + "type": "uint256" + }, + { + "name": "_candidateMinStake", + "type": "uint256" + }, + { + "name": "_stakingEpochDuration", + "type": "uint256" + }, + { + "name": "_stakingEpochStartBlock", + "type": "uint256" + }, + { + "name": "_stakeWithdrawDisallowPeriod", "type": "uint256" + }, + { + "name": "_erc20Restricted", + "type": "bool" } ], - "name": "stake", + "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "_stakingAddress", "type": "address" } ], - "name": "poolIndex", - "outputs": [ + "name": "removePool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "removeMyPool", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ { - "name": "", + "name": "_blockNumber", "type": "uint256" } ], + "name": "setStakingEpochStartBlock", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { - "name": "_poolStakingAddress", + "name": "_fromPoolStakingAddress", + "type": "address" + }, + { + "name": "_toPoolStakingAddress", "type": "address" }, { "name": "_amount", - "type": "int256" + "type": "uint256" } ], - "name": "orderWithdraw", + "name": "moveStake", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, - "inputs": [], - "name": "STAKE_UNIT", - "outputs": [ + "constant": false, + "inputs": [ { - "name": "", + "name": "_toPoolStakingAddress", + "type": "address" + }, + { + "name": "_amount", "type": "uint256" } ], + "name": "stake", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { - "name": "_poolStakingAddress", + "name": "_toPoolStakingAddress", "type": "address" } ], - "name": "claimOrderedWithdraw", + "name": "stakeNative", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_fromPoolStakingAddress", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdraw", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, - "inputs": [], - "name": "getPoolsToBeRemoved", - "outputs": [ + "constant": false, + "inputs": [ { - "name": "", - "type": "address[]" + "name": "_poolStakingAddress", + "type": "address" + }, + { + "name": "_amount", + "type": "int256" } ], + "name": "orderWithdraw", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "_poolStakingAddress", "type": "address" } ], - "name": "orderedWithdrawAmountTotal", - "outputs": [ + "name": "claimOrderedWithdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ { - "name": "", + "name": "_erc20TokenContract", + "type": "address" + } + ], + "name": "setErc20TokenContract", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_minStake", "type": "uint256" } ], + "name": "setCandidateMinStake", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_minStake", + "type": "uint256" + } + ], + "name": "setDelegatorMinStake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], - "name": "getPoolsInactive", + "name": "getPools", "outputs": [ { "name": "", @@ -641,11 +833,11 @@ { "constant": true, "inputs": [], - "name": "validatorSetContract", + "name": "getPoolsInactive", "outputs": [ { "name": "", - "type": "address" + "type": "address[]" } ], "payable": false, @@ -654,20 +846,15 @@ }, { "constant": true, - "inputs": [ + "inputs": [], + "name": "getPoolsLikelihood", + "outputs": [ { - "name": "_poolStakingAddress", - "type": "address" + "name": "likelihoods", + "type": "uint256[]" }, { - "name": "_staker", - "type": "address" - } - ], - "name": "orderedWithdrawAmount", - "outputs": [ - { - "name": "", + "name": "sum", "type": "uint256" } ], @@ -678,11 +865,11 @@ { "constant": true, "inputs": [], - "name": "MAX_DELEGATORS_PER_POOL", + "name": "getPoolsToBeElected", "outputs": [ { "name": "", - "type": "uint256" + "type": "address[]" } ], "payable": false, @@ -691,40 +878,26 @@ }, { "constant": true, - "inputs": [ - { - "name": "_stakingAddress", - "type": "address" - } - ], - "name": "poolToBeRemovedIndex", + "inputs": [], + "name": "getPoolsToBeRemoved", "outputs": [ { "name": "", - "type": "uint256" + "type": "address[]" } ], "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [], - "name": "incrementStakingEpoch", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], - "name": "MAX_CANDIDATES", + "name": "areStakeAndWithdrawAllowed", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -732,21 +905,17 @@ "type": "function" }, { - "constant": false, - "inputs": [ - { - "name": "_fromPoolStakingAddress", - "type": "address" - }, + "constant": true, + "inputs": [], + "name": "isInitialized", + "outputs": [ { - "name": "_amount", - "type": "uint256" + "name": "", + "type": "bool" } ], - "name": "withdraw", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -757,11 +926,11 @@ "type": "address" } ], - "name": "poolToBeElectedIndex", + "name": "isPoolActive", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -769,223 +938,110 @@ "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, - "name": "fromPoolStakingAddress", + "name": "_poolStakingAddress", "type": "address" }, { - "indexed": true, - "name": "staker", + "name": "_staker", "type": "address" - }, - { - "indexed": true, - "name": "stakingEpoch", - "type": "uint256" - }, - { - "indexed": false, - "name": "amount", - "type": "uint256" } ], - "name": "Claimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "toPoolStakingAddress", - "type": "address" - }, - { - "indexed": true, - "name": "staker", - "type": "address" - }, - { - "indexed": true, - "name": "stakingEpoch", - "type": "uint256" - }, + "name": "maxWithdrawAllowed", + "outputs": [ { - "indexed": false, - "name": "amount", + "name": "", "type": "uint256" } ], - "name": "Staked", - "type": "event" + "payable": false, + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": false, - "name": "fromPoolStakingAddress", - "type": "address" - }, - { - "indexed": true, - "name": "toPoolStakingAddress", + "name": "_poolStakingAddress", "type": "address" }, { - "indexed": true, - "name": "staker", + "name": "_staker", "type": "address" - }, - { - "indexed": true, - "name": "stakingEpoch", - "type": "uint256" - }, - { - "indexed": false, - "name": "amount", - "type": "uint256" } ], - "name": "StakeMoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "fromPoolStakingAddress", - "type": "address" - }, - { - "indexed": true, - "name": "staker", - "type": "address" - }, + "name": "maxWithdrawOrderAllowed", + "outputs": [ { - "indexed": true, - "name": "stakingEpoch", + "name": "", "type": "uint256" - }, - { - "indexed": false, - "name": "amount", - "type": "int256" } ], - "name": "WithdrawalOrdered", - "type": "event" + "payable": false, + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, - "name": "fromPoolStakingAddress", - "type": "address" - }, - { - "indexed": true, - "name": "staker", + "name": "", "type": "address" }, { - "indexed": true, - "name": "stakingEpoch", + "name": "", "type": "uint256" }, { - "indexed": false, - "name": "amount", - "type": "uint256" + "name": "", + "type": "bytes" } ], - "name": "Withdrawn", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "_amount", - "type": "uint256" - }, + "name": "onTokenTransfer", + "outputs": [ { - "name": "_miningAddress", - "type": "address" + "name": "", + "type": "bool" } ], - "name": "addPool", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "pure", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { - "name": "_validatorSetContract", - "type": "address" - }, - { - "name": "_erc20TokenContract", + "name": "_poolStakingAddress", "type": "address" - }, + } + ], + "name": "poolDelegators", + "outputs": [ { - "name": "_initialStakingAddresses", + "name": "", "type": "address[]" - }, - { - "name": "_delegatorMinStake", - "type": "uint256" - }, - { - "name": "_candidateMinStake", - "type": "uint256" - }, - { - "name": "_stakingEpochDuration", - "type": "uint256" - }, - { - "name": "_stakeWithdrawDisallowPeriod", - "type": "uint256" } ], - "name": "initialize", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { - "name": "_blockNumber", - "type": "uint256" + "name": "_poolStakingAddress", + "type": "address" } ], - "name": "setStakingEpochStartBlock", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "areStakeAndWithdrawAllowed", + "name": "poolDelegatorsInactive", "outputs": [ { "name": "", - "type": "bool" + "type": "address[]" } ], "payable": false, @@ -994,8 +1050,17 @@ }, { "constant": true, - "inputs": [], - "name": "stakeWithdrawDisallowPeriod", + "inputs": [ + { + "name": "_poolStakingAddress", + "type": "address" + }, + { + "name": "_staker", + "type": "address" + } + ], + "name": "stakeAmountByCurrentEpoch", "outputs": [ { "name": "", @@ -1008,8 +1073,17 @@ }, { "constant": true, - "inputs": [], - "name": "stakingEpochDuration", + "inputs": [ + { + "name": "_poolStakingAddress", + "type": "address" + }, + { + "name": "_staker", + "type": "address" + } + ], + "name": "stakeAmountMinusOrderedWithdraw", "outputs": [ { "name": "", @@ -1022,8 +1096,13 @@ }, { "constant": true, - "inputs": [], - "name": "stakingEpochStartBlock", + "inputs": [ + { + "name": "_poolStakingAddress", + "type": "address" + } + ], + "name": "stakeAmountTotalMinusOrderedWithdraw", "outputs": [ { "name": "", @@ -1048,4 +1127,4 @@ "stateMutability": "view", "type": "function" } -] \ No newline at end of file +] diff --git a/apps/explorer/priv/contracts_abi/pos/validators.json b/apps/explorer/priv/contracts_abi/posdao/ValidatorSetAuRa.json similarity index 68% rename from apps/explorer/priv/contracts_abi/pos/validators.json rename to apps/explorer/priv/contracts_abi/posdao/ValidatorSetAuRa.json index 0f0fd038c6..df164b450c 100644 --- a/apps/explorer/priv/contracts_abi/pos/validators.json +++ b/apps/explorer/priv/contracts_abi/posdao/ValidatorSetAuRa.json @@ -1,30 +1,31 @@ [ { - "constant": false, - "inputs": [], - "name": "newValidatorSet", - "outputs": [ + "constant": true, + "inputs": [ { "name": "", - "type": "bool" - }, + "type": "address" + } + ], + "name": "miningByStakingAddress", + "outputs": [ { "name": "", - "type": "uint256" + "type": "address" } ], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], - "name": "MAX_VALIDATORS", + "name": "initiateChangeAllowed", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -32,110 +33,75 @@ "type": "function" }, { + "constant": true, "inputs": [ { - "indexed": true, - "name": "parentHash", - "type": "bytes32" - }, + "name": "", + "type": "address" + } + ], + "name": "banCounter", + "outputs": [ { - "indexed": false, - "name": "newSet", - "type": "address[]" + "name": "", + "type": "uint256" } ], - "name": "InitiateChange", - "type": "event", - "anonymous": false - }, - { - "inputs": [], - "name": "clearUnremovableValidator", - "type": "function", - "constant": false, - "outputs": [], "payable": false, - "stateMutability": "nonpayable" - }, - { - "inputs": [], - "name": "emitInitiateChange", - "type": "function", - "constant": false, - "outputs": [], - "payable": false, - "stateMutability": "nonpayable" - }, - { - "inputs": [], - "name": "finalizeChange", - "type": "function", - "constant": false, - "outputs": [], - "payable": false, - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { + "constant": true, "inputs": [ { - "name": "_blockRewardContract", - "type": "address" - }, - { - "name": "_randomContract", + "name": "", "type": "address" - }, + } + ], + "name": "stakingByMiningAddress", + "outputs": [ { - "name": "_stakingContract", + "name": "", "type": "address" - }, - { - "name": "_initialMiningAddresses", - "type": "address[]" - }, - { - "name": "_initialStakingAddresses", - "type": "address[]" - }, - { - "name": "_firstValidatorIsUnremovable", - "type": "bool" } ], - "name": "initialize", - "type": "function", - "constant": false, - "outputs": [], "payable": false, - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { + "constant": true, "inputs": [ { - "name": "_miningAddress", + "name": "", "type": "address" - }, + } + ], + "name": "isValidatorOnPreviousEpoch", + "outputs": [ { - "name": "_stakingAddress", - "type": "address" + "name": "", + "type": "bool" } ], - "name": "setStakingAddress", - "type": "function", - "constant": false, - "outputs": [], "payable": false, - "stateMutability": "nonpayable" + "stateMutability": "view", + "type": "function" }, { "constant": true, "inputs": [ { - "name": "_miningAddress", + "name": "", "type": "address" + }, + { + "name": "", + "type": "uint256" } ], - "name": "banCounter", + "name": "reportingCounter", "outputs": [ { "name": "", @@ -146,11 +112,25 @@ "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "blockRewardContract", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ { - "name": "_miningAddress", + "name": "", "type": "address" } ], @@ -168,7 +148,7 @@ { "constant": true, "inputs": [], - "name": "blockRewardContract", + "name": "unremovableValidator", "outputs": [ { "name": "", @@ -182,7 +162,7 @@ { "constant": true, "inputs": [], - "name": "changeRequestCount", + "name": "MAX_VALIDATORS", "outputs": [ { "name": "", @@ -195,12 +175,17 @@ }, { "constant": true, - "inputs": [], - "name": "emitInitiateChangeCallable", + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "validatorIndex", "outputs": [ { "name": "", - "type": "bool" + "type": "uint256" } ], "payable": false, @@ -209,12 +194,17 @@ }, { "constant": true, - "inputs": [], - "name": "getPreviousValidators", + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "validatorCounter", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -224,11 +214,11 @@ { "constant": true, "inputs": [], - "name": "getPendingValidators", + "name": "validatorSetApplyBlock", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -238,15 +228,11 @@ { "constant": true, "inputs": [], - "name": "getQueueValidators", + "name": "randomContract", "outputs": [ { "name": "", - "type": "address[]" - }, - { - "name": "", - "type": "bool" + "type": "address" } ], "payable": false, @@ -256,11 +242,11 @@ { "constant": true, "inputs": [], - "name": "getValidators", + "name": "changeRequestCount", "outputs": [ { "name": "", - "type": "address[]" + "type": "uint256" } ], "payable": false, @@ -269,12 +255,17 @@ }, { "constant": true, - "inputs": [], - "name": "initiateChangeAllowed", + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "reportingCounterTotal", "outputs": [ { "name": "", - "type": "bool" + "type": "uint256" } ], "payable": false, @@ -285,15 +276,37 @@ "constant": true, "inputs": [ { - "name": "_miningAddress", + "name": "", "type": "address" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" } ], - "name": "isReportValidatorValid", + "name": "maliceReportedForBlock", "outputs": [ { "name": "", - "type": "bool" + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "stakingContract", + "outputs": [ + { + "name": "", + "type": "address" } ], "payable": false, @@ -304,7 +317,7 @@ "constant": true, "inputs": [ { - "name": "_miningAddress", + "name": "", "type": "address" } ], @@ -320,56 +333,185 @@ "type": "function" }, { - "constant": true, + "anonymous": false, "inputs": [ { - "name": "_miningAddress", + "indexed": true, + "name": "parentHash", + "type": "bytes32" + }, + { + "indexed": false, + "name": "newSet", + "type": "address[]" + } + ], + "name": "InitiateChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "reportingValidator", + "type": "address" + }, + { + "indexed": false, + "name": "maliciousValidator", "type": "address" + }, + { + "indexed": false, + "name": "blockNumber", + "type": "uint256" } ], - "name": "isValidatorOnPreviousEpoch", + "name": "ReportedMalicious", + "type": "event" + }, + { + "constant": false, + "inputs": [], + "name": "clearUnremovableValidator", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "emitInitiateChange", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "finalizeChange", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_blockRewardContract", + "type": "address" + }, + { + "name": "_randomContract", + "type": "address" + }, + { + "name": "_stakingContract", + "type": "address" + }, + { + "name": "_initialMiningAddresses", + "type": "address[]" + }, + { + "name": "_initialStakingAddresses", + "type": "address[]" + }, + { + "name": "_firstValidatorIsUnremovable", + "type": "bool" + } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "newValidatorSet", "outputs": [ { - "name": "", + "name": "called", "type": "bool" + }, + { + "name": "poolsToBeElectedLength", + "type": "uint256" } ], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { - "name": "_miningAddress", - "type": "address" + "name": "_miningAddresses", + "type": "address[]" } ], - "name": "isValidatorBanned", - "outputs": [ + "name": "removeMaliciousValidators", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_maliciousMiningAddress", + "type": "address" + }, + { + "name": "_blockNumber", + "type": "uint256" + }, { "name": "", - "type": "bool" + "type": "bytes" } ], + "name": "reportMalicious", + "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ + { + "name": "_miningAddress", + "type": "address" + }, { "name": "_stakingAddress", "type": "address" } ], - "name": "miningByStakingAddress", + "name": "setStakingAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "emitInitiateChangeCallable", "outputs": [ { "name": "", - "type": "address" + "type": "bool" } ], "payable": false, @@ -379,11 +521,11 @@ { "constant": true, "inputs": [], - "name": "randomContract", + "name": "getPreviousValidators", "outputs": [ { "name": "", - "type": "address" + "type": "address[]" } ], "payable": false, @@ -392,17 +534,30 @@ }, { "constant": true, - "inputs": [ + "inputs": [], + "name": "getPendingValidators", + "outputs": [ { - "name": "_miningAddress", - "type": "address" + "name": "", + "type": "address[]" } ], - "name": "stakingByMiningAddress", + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getQueueValidators", "outputs": [ { - "name": "", - "type": "address" + "name": "miningAddresses", + "type": "address[]" + }, + { + "name": "newStakingEpoch", + "type": "bool" } ], "payable": false, @@ -412,11 +567,11 @@ { "constant": true, "inputs": [], - "name": "stakingContract", + "name": "getValidators", "outputs": [ { "name": "", - "type": "address" + "type": "address[]" } ], "payable": false, @@ -426,11 +581,11 @@ { "constant": true, "inputs": [], - "name": "unremovableValidator", + "name": "isInitialized", "outputs": [ { - "name": "stakingAddress", - "type": "address" + "name": "", + "type": "bool" } ], "payable": false, @@ -445,11 +600,11 @@ "type": "address" } ], - "name": "validatorCounter", + "name": "isReportValidatorValid", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -464,11 +619,11 @@ "type": "address" } ], - "name": "validatorIndex", + "name": "isValidatorBanned", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -477,16 +632,33 @@ }, { "constant": true, - "inputs": [], - "name": "validatorSetApplyBlock", - "outputs": [ + "inputs": [ { - "name": "", + "name": "_reportingMiningAddress", + "type": "address" + }, + { + "name": "_maliciousMiningAddress", + "type": "address" + }, + { + "name": "_blockNumber", "type": "uint256" } ], + "name": "reportMaliciousCallable", + "outputs": [ + { + "name": "callable", + "type": "bool" + }, + { + "name": "removeReportingValidator", + "type": "bool" + } + ], "payable": false, "stateMutability": "view", "type": "function" } -] \ No newline at end of file +] diff --git a/apps/explorer/priv/repo/migrations/20190605125829_delegators_deleted_colum.exs b/apps/explorer/priv/repo/migrations/20190605125829_delegators_deleted_colum.exs new file mode 100644 index 0000000000..36d0b8e837 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190605125829_delegators_deleted_colum.exs @@ -0,0 +1,10 @@ +defmodule Explorer.Repo.Migrations.DelegatorsDeletedColum do + use Ecto.Migration + + def change do + alter table(:staking_pools_delegators) do + add(:is_active, :boolean, default: true) + add(:is_deleted, :boolean, default: false) + end + end +end diff --git a/apps/explorer/priv/repo/migrations/20190718175620_add_block_reward_to_pools.exs b/apps/explorer/priv/repo/migrations/20190718175620_add_block_reward_to_pools.exs new file mode 100644 index 0000000000..b84376ab6e --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190718175620_add_block_reward_to_pools.exs @@ -0,0 +1,9 @@ +defmodule Explorer.Repo.Migrations.AddBlockRewardToPools do + use Ecto.Migration + + def change do + alter table(:staking_pools) do + add(:block_reward_ratio, :decimal, precision: 5, scale: 2) + end + end +end diff --git a/apps/explorer/test/explorer/chain/import/runner/staking_pools_test.exs b/apps/explorer/test/explorer/chain/import/runner/staking_pools_test.exs index 1c56fe294c..91c79b6132 100644 --- a/apps/explorer/test/explorer/chain/import/runner/staking_pools_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/staking_pools_test.exs @@ -10,7 +10,7 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsTest do describe "run/1" do test "insert new pools list" do pools = - [pool1, pool2] = + [_pool1, _pool2] = [params_for(:staking_pool), params_for(:staking_pool)] |> Enum.map(fn param -> changeset = StakingPool.changeset(%StakingPool{}, param) @@ -19,16 +19,6 @@ defmodule Explorer.Chain.Import.Runner.StakingPoolsTest do assert {:ok, %{insert_staking_pools: list}} = run_changes(pools) assert Enum.count(list) == Enum.count(pools) - - saved_list = - Explorer.Chain.StakingPool - |> Repo.all() - |> Enum.reduce(%{}, fn pool, acc -> - Map.put(acc, pool.staking_address_hash, pool) - end) - - assert saved_list[pool1.staking_address_hash].staked_ratio == Decimal.new("50.00") - assert saved_list[pool2.staking_address_hash].staked_ratio == Decimal.new("50.00") end end diff --git a/apps/explorer/test/explorer/staking/contract_state_test.exs b/apps/explorer/test/explorer/staking/contract_state_test.exs new file mode 100644 index 0000000000..cfdad1831e --- /dev/null +++ b/apps/explorer/test/explorer/staking/contract_state_test.exs @@ -0,0 +1,208 @@ +defmodule Explorer.Staking.ContractStateTest do + use EthereumJSONRPC.Case + use Explorer.DataCase + + import Mox + + alias Explorer.Chain.{StakingPool, StakingPoolsDelegator} + alias Explorer.Chain.Events.Publisher + alias Explorer.Repo + alias Explorer.Staking.ContractState + + setup :verify_on_exit! + setup :set_mox_global + + test "when disabled, returns default values" do + assert ContractState.get(:epoch_number, 0) == 0 + assert ContractState.get(:epoch_end_block, 0) == 0 + assert ContractState.get(:min_delegator_stake, 1) == 1 + assert ContractState.get(:min_candidate_stake, 1) == 1 + assert ContractState.get(:token_contract_address) == nil + end + + test "fetch new epoch data" do + set_init_mox() + set_mox() + + Application.put_env(:explorer, ContractState, + enabled: true, + staking_contract_address: "0x1100000000000000000000000000000000000001" + ) + + start_supervised!(ContractState) + + set_mox() + Publisher.broadcast([{:blocks, [%Explorer.Chain.Block{number: 6000}]}], :realtime) + Publisher.broadcast([{:blocks, [%Explorer.Chain.Block{number: 5999}]}], :realtime) + Publisher.broadcast([{:blocks, [%Explorer.Chain.Block{number: 6000}]}], :realtime) + + set_mox() + Publisher.broadcast([{:blocks, [%Explorer.Chain.Block{number: 6001}]}], :realtime) + + Process.sleep(500) + + assert ContractState.get(:epoch_number) == 74 + assert ContractState.get(:epoch_end_block) == 6000 + assert ContractState.get(:min_delegator_stake) == 1_000_000_000_000_000_000 + assert ContractState.get(:min_candidate_stake) == 1_000_000_000_000_000_000 + assert ContractState.get(:token_contract_address) == "0x6f7a73c96bd56f8b0debc795511eda135e105ea3" + + assert Repo.aggregate(StakingPool, :count, :id) == 4 + assert Repo.aggregate(StakingPoolsDelegator, :count, :id) == 3 + end + + defp set_init_mox() do + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 1 + {:ok, format_responses(["0x0000000000000000000000001000000000000000000000000000000000000001"])} + end + ) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 1 + {:ok, format_responses(["0x0000000000000000000000002000000000000000000000000000000000000001"])} + end + ) + end + + defp set_mox() do + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 10 + + {:ok, + format_responses([ + "0x0000000000000000000000006f7a73c96bd56f8b0debc795511eda135e105ea3", + "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", + "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", + "0x000000000000000000000000000000000000000000000000000000000000004a", + "0x0000000000000000000000000000000000000000000000000000000000001770", + "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6000000000000000000000000b916e7e1f4bcb13549602ed042d36746fd0d96c9000000000000000000000000db9cb2478d917719c53862008672166808258577", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b6695f5c2e3f5eff8036b5f5f3a9d83a5310e51e", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b916e7e1f4bcb13549602ed042d36746fd0d96c9000000000000000000000000db9cb2478d917719c53862008672166808258577", + "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000514000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000044c", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78000000000000000000000000f67cc5231c5858ad6cc87b105217426e17b824bb000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3" + ])} + end + ) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 28 + + {:ok, + format_responses([ + "0x000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000003d090", + "0x000000000000000000000000f67cc5231c5858ad6cc87b105217426e17b824bb", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000001bc16d674ec80000", + "0x0000000000000000000000000000000000000000000000001bc16d674ec80000", + "0x0000000000000000000000000000000000000000000000000000000000051615", + "0x000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009d99f80d3b59cca783f11918311fb31212fb7500000000000000000000000008d6867958e1cab5c39160a1d30fbc68ac55b45ef", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000098a7d9b8314c0000", + "0x0000000000000000000000000000000000000000000000001bc16d674ec80000", + "0x0000000000000000000000000000000000000000000000000000000000051615", + "0x000000000000000000000000720e118ab1006cc97ed2ef6b4b49ac04bb3aa6d9", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e4978fac7adfc925352dbc7e1962e6545142eeee", + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000029a2241af62c0000", + "0x0000000000000000000000000000000000000000000000001bc16d674ec80000", + "0x0000000000000000000000000000000000000000000000000000000000051615" + ])} + end + ) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 20 + + {:ok, + format_responses([ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000004b", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000004a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000004a", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ])} + end + ) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn requests, _opts -> + assert length(requests) == 15 + + {:ok, + format_responses([ + "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ])} + end + ) + end + + defp format_responses(responses) do + responses + |> Enum.with_index() + |> Enum.map(fn {response, index} -> + %{ + id: index, + jsonrpc: "2.0", + result: response + } + end) + end +end diff --git a/apps/explorer/test/explorer/staking/epoch_counter_test.exs b/apps/explorer/test/explorer/staking/epoch_counter_test.exs deleted file mode 100644 index 278377ce05..0000000000 --- a/apps/explorer/test/explorer/staking/epoch_counter_test.exs +++ /dev/null @@ -1,97 +0,0 @@ -defmodule Explorer.Staking.EpochCounterTest do - use ExUnit.Case, async: false - - import Mox - - alias Explorer.Staking.EpochCounter - alias Explorer.Chain.Events.Publisher - - setup :verify_on_exit! - setup :set_mox_global - - test "when disabled, it returns nil" do - assert EpochCounter.epoch_number() == nil - assert EpochCounter.epoch_end_block() == nil - end - - test "fetch epoch data" do - set_mox(10, 880) - Application.put_env(:explorer, EpochCounter, enabled: true) - start_supervised!(EpochCounter) - - Process.sleep(1_000) - - assert EpochCounter.epoch_number() == 10 - assert EpochCounter.epoch_end_block() == 880 - end - - test "fetch new epoch data" do - set_mox(10, 880) - Application.put_env(:explorer, EpochCounter, enabled: true) - start_supervised!(EpochCounter) - - Process.sleep(1_000) - - assert EpochCounter.epoch_number() == 10 - assert EpochCounter.epoch_end_block() == 880 - - event_type = :blocks - broadcast_type = :realtime - event_data = [%Explorer.Chain.Block{number: 881}] - - set_mox(11, 960) - Publisher.broadcast([{event_type, event_data}], broadcast_type) - - Process.sleep(1_000) - - assert EpochCounter.epoch_number() == 11 - assert EpochCounter.epoch_end_block() == 960 - end - - defp set_mox(epoch_num, end_block_num) do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - fn [ - %{ - id: 0, - jsonrpc: "2.0", - method: "eth_call", - params: _ - }, - %{ - id: 1, - jsonrpc: "2.0", - method: "eth_call", - params: _ - } - ], - _options -> - {:ok, - [ - %{ - id: 0, - jsonrpc: "2.0", - result: encode_num(epoch_num) - }, - %{ - id: 1, - jsonrpc: "2.0", - result: encode_num(end_block_num) - } - ]} - end - ) - end - - defp encode_num(num) do - selector = %ABI.FunctionSelector{function: nil, types: [uint: 32]} - - encoded_num = - [num] - |> ABI.TypeEncoder.encode(selector) - |> Base.encode16(case: :lower) - - "0x" <> encoded_num - end -end diff --git a/apps/explorer/test/explorer/staking/pools_reader_test.exs b/apps/explorer/test/explorer/staking/pools_reader_test.exs deleted file mode 100644 index 6fb5940010..0000000000 --- a/apps/explorer/test/explorer/staking/pools_reader_test.exs +++ /dev/null @@ -1,361 +0,0 @@ -defmodule Explorer.Token.PoolsReaderTest do - use EthereumJSONRPC.Case - - alias Explorer.Staking.PoolsReader - - import Mox - - setup :verify_on_exit! - setup :set_mox_global - - describe "get_pools_list" do - test "get_active_pools success" do - get_pools_from_blockchain() - - result = PoolsReader.get_active_pools() - - assert Enum.count(result) == 3 - end - - test "get_active_pools error" do - fetch_from_blockchain_with_error() - - assert_raise MatchError, fn -> - PoolsReader.get_active_pools() - end - end - end - - describe "get_pools_data" do - test "get_pool_data success" do - get_pool_data_from_blockchain() - - address = <<219, 156, 178, 71, 141, 145, 119, 25, 197, 56, 98, 0, 134, 114, 22, 104, 8, 37, 133, 119>> - - response = - {:ok, - %{ - banned_until: 0, - is_active: true, - is_banned: false, - is_validator: true, - was_banned_count: 0, - was_validator_count: 2, - delegators: [ - %{ - delegator_address_hash: - <<243, 231, 124, 74, 245, 235, 47, 51, 175, 255, 118, 25, 216, 209, 231, 81, 215, 24, 164, 145>>, - max_ordered_withdraw_allowed: 1_000_000_000_000_000_000, - max_withdraw_allowed: 1_000_000_000_000_000_000, - ordered_withdraw: 0, - ordered_withdraw_epoch: 0, - pool_address_hash: - <<219, 156, 178, 71, 141, 145, 119, 25, 197, 56, 98, 0, 134, 114, 22, 104, 8, 37, 133, 119>>, - stake_amount: 1_000_000_000_000_000_000 - } - ], - delegators_count: 1, - mining_address_hash: - <<190, 105, 235, 9, 104, 34, 106, 24, 8, 151, 94, 26, 31, 33, 39, 102, 127, 43, 255, 179>>, - self_staked_amount: 2_000_000_000_000_000_000, - staked_amount: 3_000_000_000_000_000_000, - staking_address_hash: - <<219, 156, 178, 71, 141, 145, 119, 25, 197, 56, 98, 0, 134, 114, 22, 104, 8, 37, 133, 119>> - }} - - assert PoolsReader.pool_data(address) == response - end - - test "get_pool_data error" do - fetch_from_blockchain_with_error() - - address = <<11, 47, 94, 47, 60, 189, 134, 78, 170, 44, 100, 46, 55, 105, 193, 88, 35, 97, 202, 246>> - - assert :error = PoolsReader.pool_data(address) - end - end - - defp get_pools_from_blockchain() do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - fn [%{id: id, method: "eth_call", params: _}], _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: - "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6000000000000000000000000aa94b687d3f9552a453b81b2834ca53778980dc0000000000000000000000000312c230e7d6db05224f60208a656e3541c5c42ba" - } - ]} - end - ) - end - - defp fetch_from_blockchain_with_error() do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - fn [%{id: id, method: "eth_call", params: _}], _options -> - {:ok, - [ - %{ - error: %{code: -32015, data: "Reverted 0x", message: "VM execution error."}, - id: id, - jsonrpc: "2.0" - } - ]} - end - ) - end - - defp get_pool_data_from_blockchain() do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - 3, - fn requests, _opts -> - {:ok, - Enum.map(requests, fn - # miningByStakingAddress - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x00535175000000000000000000000000db9cb2478d917719c53862008672166808258577", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3" - } - - # isPoolActive - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xa711e6a1000000000000000000000000db9cb2478d917719c53862008672166808258577", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000001" - } - - # poolDelegators - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x9ea8082b000000000000000000000000db9cb2478d917719c53862008672166808258577", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: - "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491" - } - - # stakeAmountTotalMinusOrderedWithdraw - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x234fbf2b000000000000000000000000db9cb2478d917719c53862008672166808258577", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x00000000000000000000000000000000000000000000000029a2241af62c0000" - } - - # stakeAmountMinusOrderedWithdraw - %{ - id: id, - jsonrpc: "2.0", - method: "eth_call", - params: [ - %{ - data: - "0x58daab6a000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000db9cb2478d917719c53862008672166808258577", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000001bc16d674ec80000" - } - - # isValidator - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xfacd743b000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000001" - } - - # validatorCounter - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xb41832e4000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000002" - } - - # isValidatorBanned - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xa92252ae000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # bannedUntil - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x5836d08a000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # banCounter - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x1d0cd4c6000000000000000000000000be69eb0968226a1808975e1a1f2127667f2bffb3", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # DELEGATOR - # stakeAmount - %{ - id: id, - method: "eth_call", - params: [ - %{ - data: - "0xa697ecff000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - } - - # orderedWithdrawAmount - %{ - id: id, - method: "eth_call", - params: [ - %{ - data: - "0xe9ab0300000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # maxWithdrawAllowed - %{ - id: id, - method: "eth_call", - params: [ - %{ - data: - "0x6bda1577000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - } - - # maxWithdrawOrderAllowed - %{ - id: id, - method: "eth_call", - params: [ - %{ - data: - "0x950a6513000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" - } - - # orderWithdrawEpoch - %{ - id: id, - method: "eth_call", - params: [ - %{ - data: - "0xa4205967000000000000000000000000db9cb2478d917719c53862008672166808258577000000000000000000000000f3e77c4af5eb2f33afff7619d8d1e751d718a491", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - end)} - end - ) - end -end diff --git a/apps/indexer/config/config.exs b/apps/indexer/config/config.exs index 24b9edd909..2421ae8c16 100644 --- a/apps/indexer/config/config.exs +++ b/apps/indexer/config/config.exs @@ -42,8 +42,9 @@ config :indexer, Indexer.Fetcher.PendingTransaction.Supervisor, disabled?: System.get_env("ETHEREUM_JSONRPC_VARIANT") == "besu" # config :indexer, Indexer.Fetcher.ReplacedTransaction.Supervisor, disabled?: true -# config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: true -config :indexer, Indexer.Fetcher.StakingPools.Supervisor, disabled?: true +if System.get_env("POS_STAKING_CONTRACT") do + config :indexer, Indexer.Fetcher.BlockReward.Supervisor, disabled?: true +end config :indexer, Indexer.Supervisor, enabled: System.get_env("DISABLE_INDEXER") != "true" diff --git a/apps/indexer/lib/indexer/block/fetcher.ex b/apps/indexer/lib/indexer/block/fetcher.ex index 40ed68c6f6..86e2c84ada 100644 --- a/apps/indexer/lib/indexer/block/fetcher.ex +++ b/apps/indexer/lib/indexer/block/fetcher.ex @@ -23,7 +23,6 @@ defmodule Indexer.Block.Fetcher do ContractCode, InternalTransaction, ReplacedTransaction, - StakingPools, Token, TokenBalance, TokenInstance, @@ -307,10 +306,6 @@ defmodule Indexer.Block.Fetcher do def async_import_token_balances(_), do: :ok - def async_import_staking_pools do - StakingPools.async_fetch() - end - def async_import_uncles(%{block_second_degree_relations: block_second_degree_relations}) do UncleBlock.async_fetch_blocks(block_second_degree_relations) end diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index df4daa5837..af9dac4c4d 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -21,8 +21,7 @@ defmodule Indexer.Block.Realtime.Fetcher do async_import_token_balances: 1, async_import_token_instances: 1, async_import_uncles: 1, - fetch_and_import_range: 2, - async_import_staking_pools: 0 + fetch_and_import_range: 2 ] alias Ecto.Changeset @@ -369,7 +368,6 @@ defmodule Indexer.Block.Realtime.Fetcher do async_import_token_instances(imported) async_import_uncles(imported) async_import_replaced_transactions(imported) - async_import_staking_pools() end defp balances( diff --git a/apps/indexer/lib/indexer/fetcher/staking_pools.ex b/apps/indexer/lib/indexer/fetcher/staking_pools.ex deleted file mode 100644 index 1576eb56e2..0000000000 --- a/apps/indexer/lib/indexer/fetcher/staking_pools.ex +++ /dev/null @@ -1,140 +0,0 @@ -defmodule Indexer.Fetcher.StakingPools do - @moduledoc """ - Fetches staking pools and send to be imported in `Address.Name` table - """ - - use Indexer.Fetcher - use Spandex.Decorators - - require Logger - - alias Explorer.Chain - alias Explorer.Chain.StakingPool - alias Explorer.Staking.PoolsReader - alias Indexer.BufferedTask - alias Indexer.Fetcher.StakingPools.Supervisor, as: StakingPoolsSupervisor - - @behaviour BufferedTask - - @defaults [ - flush_interval: 300, - max_batch_size: 100, - max_concurrency: 10, - task_supervisor: Indexer.Fetcher.StakingPools.TaskSupervisor - ] - - @max_retries 3 - - @spec async_fetch() :: :ok - def async_fetch do - if StakingPoolsSupervisor.disabled?() do - :ok - else - pools = - PoolsReader.get_pools() - |> Enum.map(&entry/1) - - BufferedTask.buffer(__MODULE__, pools, :infinity) - end - end - - @doc false - def child_spec([init_options, gen_server_options]) do - merged_init_opts = - @defaults - |> Keyword.merge(init_options) - |> Keyword.put(:state, {0, []}) - - Supervisor.child_spec({BufferedTask, [{__MODULE__, merged_init_opts}, gen_server_options]}, id: __MODULE__) - end - - @impl BufferedTask - def init(_initial, reducer, acc) do - PoolsReader.get_pools() - |> Enum.map(&entry/1) - |> Enum.reduce(acc, &reducer.(&1, &2)) - end - - @impl BufferedTask - def run(pools, _json_rpc_named_arguments) do - failed_list = - pools - |> Enum.map(&Map.put(&1, :retries_count, &1.retries_count + 1)) - |> fetch_from_blockchain() - |> import_pools() - - if failed_list == [] do - :ok - else - {:retry, failed_list} - end - end - - def entry(pool_address) do - %{ - staking_address_hash: pool_address, - retries_count: 0 - } - end - - defp fetch_from_blockchain(addresses) do - addresses - |> Enum.filter(&(&1.retries_count <= @max_retries)) - |> Enum.map(fn %{staking_address_hash: staking_address} = pool -> - case PoolsReader.pool_data(staking_address) do - {:ok, data} -> - Map.merge(pool, data) - - error -> - Map.put(pool, :error, error) - end - end) - end - - defp import_pools(pools) do - {failed, success} = - Enum.reduce(pools, {[], []}, fn - %{error: _error} = pool, {failed, success} -> - {[pool | failed], success} - - pool, {failed, success} -> - changeset = StakingPool.changeset(%StakingPool{}, pool) - - if changeset.valid? do - {failed, [changeset.changes | success]} - else - {[pool | failed], success} - end - end) - - import_params = %{ - staking_pools: %{params: remove_assoc(success)}, - staking_pools_delegators: %{params: delegators_list(success)}, - timeout: :infinity - } - - case Chain.import(import_params) do - {:ok, _} -> - :ok - - {:error, reason} -> - Logger.debug(fn -> ["failed to import staking pools: ", inspect(reason)] end, - error_count: Enum.count(pools) - ) - end - - failed - end - - defp delegators_list(pools) do - Enum.reduce(pools, [], fn pool, acc -> - pool.delegators - |> Enum.map(&Map.get(&1, :changes)) - |> Enum.concat(acc) - end) - end - - defp remove_assoc(pools) do - Enum.map(pools, &Map.delete(&1, :delegators)) - end -end diff --git a/apps/indexer/lib/indexer/supervisor.ex b/apps/indexer/lib/indexer/supervisor.ex index f105c0eaec..a55c17e945 100644 --- a/apps/indexer/lib/indexer/supervisor.ex +++ b/apps/indexer/lib/indexer/supervisor.ex @@ -16,7 +16,6 @@ defmodule Indexer.Supervisor do InternalTransaction, PendingTransaction, ReplacedTransaction, - StakingPools, Token, TokenBalance, TokenInstance, @@ -114,7 +113,6 @@ defmodule Indexer.Supervisor do {TokenBalance.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, {TokenUpdater.Supervisor, [[json_rpc_named_arguments: json_rpc_named_arguments, memory_monitor: memory_monitor]]}, {ReplacedTransaction.Supervisor, [[memory_monitor: memory_monitor]]}, - {StakingPools.Supervisor, [[memory_monitor: memory_monitor]]}, # Out-of-band fetchers {CoinBalanceOnDemand.Supervisor, [json_rpc_named_arguments]}, diff --git a/apps/indexer/test/indexer/fetcher/staking_pools_test.exs b/apps/indexer/test/indexer/fetcher/staking_pools_test.exs deleted file mode 100644 index 257c9e558c..0000000000 --- a/apps/indexer/test/indexer/fetcher/staking_pools_test.exs +++ /dev/null @@ -1,224 +0,0 @@ -defmodule Indexer.Fetcher.StakingPoolsTest do - use EthereumJSONRPC.Case - use Explorer.DataCase - - import Mox - - alias Indexer.Fetcher.StakingPools - alias Explorer.Staking.PoolsReader - alias Explorer.Chain.StakingPool - - @moduletag :capture_log - - setup :verify_on_exit! - - describe "init/3" do - test "returns pools addresses" do - get_pools_from_blockchain(2) - - list = StakingPools.init([], &[&1 | &2], []) - - assert Enum.count(list) == 6 - end - end - - describe "run/3" do - test "one success import from pools" do - get_pools_from_blockchain(1) - - list = - PoolsReader.get_active_pools() - |> Enum.map(&StakingPools.entry/1) - - success_address = - list - |> List.first() - |> Map.get(:staking_address_hash) - - get_pool_data_from_blockchain() - - assert {:retry, retry_list} = StakingPools.run(list, nil) - assert Enum.count(retry_list) == 2 - - pool = Explorer.Repo.get_by(StakingPool, staking_address_hash: success_address) - assert pool.is_active == true - end - end - - defp get_pools_from_blockchain(n) do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - n, - fn [%{id: id, method: "eth_call", params: _}], _options -> - {:ok, - [ - %{ - id: id, - jsonrpc: "2.0", - result: - "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6000000000000000000000000aa94b687d3f9552a453b81b2834ca53778980dc0000000000000000000000000312c230e7d6db05224f60208a656e3541c5c42ba" - } - ]} - end - ) - end - - defp get_pool_data_from_blockchain() do - expect( - EthereumJSONRPC.Mox, - :json_rpc, - 4, - fn requests, _opts -> - {:ok, - Enum.map(requests, fn - # miningByStakingAddress - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x005351750000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78" - } - - # isPoolActive - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xa711e6a10000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000001" - } - - # poolDelegators - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x9ea8082b0000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: - "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - } - - # stakeAmountTotalMinusOrderedWithdraw - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x234fbf2b0000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # stakeAmountMinusOrderedWithdraw - %{ - id: id, - jsonrpc: "2.0", - method: "eth_call", - params: [ - %{ - data: - "0x58daab6a0000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf60000000000000000000000000b2f5e2f3cbd864eaa2c642e3769c1582361caf6", - to: _ - }, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # isValidator - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xfacd743b000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000001" - } - - # validatorCounter - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xb41832e4000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000002" - } - - # isValidatorBanned - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0xa92252ae000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # bannedUntil - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x5836d08a000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - - # banCounter - %{ - id: id, - method: "eth_call", - params: [ - %{data: "0x1d0cd4c6000000000000000000000000bbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", to: _}, - "latest" - ] - } -> - %{ - id: id, - result: "0x0000000000000000000000000000000000000000000000000000000000000000" - } - end)} - end - ) - end -end