commit
2d644214ab
@ -0,0 +1,88 @@ |
|||||||
|
defmodule Explorer.Chain.Import.Runner.StakingPools do |
||||||
|
@moduledoc """ |
||||||
|
Bulk imports staking pools to Address.Name tabe. |
||||||
|
""" |
||||||
|
|
||||||
|
require Ecto.Query |
||||||
|
|
||||||
|
alias Ecto.{Changeset, Multi, Repo} |
||||||
|
alias Explorer.Chain.{Address, Import} |
||||||
|
|
||||||
|
import Ecto.Query, only: [from: 2] |
||||||
|
|
||||||
|
@behaviour Import.Runner |
||||||
|
|
||||||
|
# milliseconds |
||||||
|
@timeout 60_000 |
||||||
|
|
||||||
|
@type imported :: [Address.Name.t()] |
||||||
|
|
||||||
|
@impl Import.Runner |
||||||
|
def ecto_schema_module, do: Address.Name |
||||||
|
|
||||||
|
@impl Import.Runner |
||||||
|
def option_key, do: :staking_pools |
||||||
|
|
||||||
|
@impl Import.Runner |
||||||
|
def imported_table_row do |
||||||
|
%{ |
||||||
|
value_type: "[#{ecto_schema_module()}.t()]", |
||||||
|
value_description: "List of `t:#{ecto_schema_module()}.t/0`s" |
||||||
|
} |
||||||
|
end |
||||||
|
|
||||||
|
@impl Import.Runner |
||||||
|
def run(multi, changes_list, %{timestamps: timestamps} = options) do |
||||||
|
insert_options = |
||||||
|
options |
||||||
|
|> Map.get(option_key(), %{}) |
||||||
|
|> Map.take(~w(on_conflict timeout)a) |
||||||
|
|> Map.put_new(:timeout, @timeout) |
||||||
|
|> Map.put(:timestamps, timestamps) |
||||||
|
|
||||||
|
multi |
||||||
|
|> Multi.run(:insert_staking_pools, fn repo, _ -> |
||||||
|
insert(repo, changes_list, insert_options) |
||||||
|
end) |
||||||
|
end |
||||||
|
|
||||||
|
@impl Import.Runner |
||||||
|
def timeout, do: @timeout |
||||||
|
|
||||||
|
@spec insert(Repo.t(), [map()], %{ |
||||||
|
optional(:on_conflict) => Import.Runner.on_conflict(), |
||||||
|
required(:timeout) => timeout, |
||||||
|
required(:timestamps) => Import.timestamps() |
||||||
|
}) :: |
||||||
|
{:ok, [Address.Name.t()]} |
||||||
|
| {:error, [Changeset.t()]} |
||||||
|
defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do |
||||||
|
on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) |
||||||
|
|
||||||
|
{:ok, _} = |
||||||
|
Import.insert_changes_list( |
||||||
|
repo, |
||||||
|
changes_list, |
||||||
|
conflict_target: {:unsafe_fragment, "(address_hash) where \"primary\" = true"}, |
||||||
|
on_conflict: on_conflict, |
||||||
|
for: Address.Name, |
||||||
|
returning: [:address_hash], |
||||||
|
timeout: timeout, |
||||||
|
timestamps: timestamps |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
defp default_on_conflict do |
||||||
|
from( |
||||||
|
name in Address.Name, |
||||||
|
update: [ |
||||||
|
set: [ |
||||||
|
name: fragment("EXCLUDED.name"), |
||||||
|
metadata: fragment("EXCLUDED.metadata"), |
||||||
|
inserted_at: fragment("LEAST(?, EXCLUDED.inserted_at)", name.inserted_at), |
||||||
|
updated_at: fragment("GREATEST(?, EXCLUDED.updated_at)", name.updated_at) |
||||||
|
] |
||||||
|
] |
||||||
|
) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,121 @@ |
|||||||
|
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 |
||||||
|
{:ok, [active_pools]} = call_staking_method("getPools", []) |
||||||
|
active_pools |
||||||
|
end |
||||||
|
|
||||||
|
@spec get_inactive_pools() :: [String.t()] |
||||||
|
def get_inactive_pools do |
||||||
|
{:ok, [inactive_pools]} = call_staking_method("getPoolsInactive", []) |
||||||
|
inactive_pools |
||||||
|
end |
||||||
|
|
||||||
|
@spec pool_data(String.t()) :: {:ok, map()} | :error |
||||||
|
def pool_data(staking_address) do |
||||||
|
with {:ok, [mining_address]} <- call_validators_method("miningByStakingAddress", [staking_address]), |
||||||
|
data = fetch_data(staking_address, mining_address), |
||||||
|
{:ok, [is_active]} <- data["isPoolActive"], |
||||||
|
{:ok, [delegator_addresses]} <- data["poolDelegators"], |
||||||
|
delegators_count = Enum.count(delegator_addresses), |
||||||
|
{:ok, [staked_amount]} <- data["stakeAmountTotalMinusOrderedWithdraw"], |
||||||
|
{:ok, [is_validator]} <- data["isValidator"], |
||||||
|
{:ok, [was_validator_count]} <- data["validatorCounter"], |
||||||
|
{:ok, [is_banned]} <- data["isValidatorBanned"], |
||||||
|
{:ok, [banned_until]} <- data["bannedUntil"], |
||||||
|
{:ok, [was_banned_count]} <- data["banCounter"] do |
||||||
|
{ |
||||||
|
:ok, |
||||||
|
%{ |
||||||
|
staking_address: staking_address, |
||||||
|
mining_address: mining_address, |
||||||
|
is_active: is_active, |
||||||
|
delegators_count: delegators_count, |
||||||
|
staked_amount: 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 |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
_ -> |
||||||
|
:error |
||||||
|
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_data(staking_address, mining_address) do |
||||||
|
contract_abi = abi("staking.json") ++ abi("validators.json") |
||||||
|
|
||||||
|
methods = [ |
||||||
|
{:staking, "isPoolActive", staking_address}, |
||||||
|
{:staking, "poolDelegators", staking_address}, |
||||||
|
{:staking, "stakeAmountTotalMinusOrderedWithdraw", staking_address}, |
||||||
|
{:validators, "isValidator", mining_address}, |
||||||
|
{:validators, "validatorCounter", mining_address}, |
||||||
|
{:validators, "isValidatorBanned", mining_address}, |
||||||
|
{:validators, "bannedUntil", mining_address}, |
||||||
|
{:validators, "banCounter", mining_address} |
||||||
|
] |
||||||
|
|
||||||
|
methods |
||||||
|
|> Enum.map(&format_request/1) |
||||||
|
|> Reader.query_contracts(contract_abi) |
||||||
|
|> Enum.zip(methods) |
||||||
|
|> Enum.into(%{}, fn {response, {_, function_name, _}} -> |
||||||
|
{function_name, response} |
||||||
|
end) |
||||||
|
end |
||||||
|
|
||||||
|
defp format_request({contract_name, function_name, param}) do |
||||||
|
%{ |
||||||
|
contract_address: contract(contract_name), |
||||||
|
function_name: function_name, |
||||||
|
args: [param] |
||||||
|
} |
||||||
|
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 |
@ -0,0 +1,925 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "STAKE_UNIT", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "MAX_DELEGATORS_PER_POOL", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "MAX_CANDIDATES", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"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": "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": "_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": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "removePool", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "removePool", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_fromPoolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_toPoolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_amount", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "moveStake", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_toPoolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_amount", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stake", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_fromPoolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_amount", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "withdraw", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_amount", |
||||||
|
"type": "int256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "orderWithdraw", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "claimOrderedWithdraw", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"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": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_minStake", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "setDelegatorMinStake", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPools", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPoolsInactive", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPoolsLikelihood", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "likelihoods", |
||||||
|
"type": "int256[]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "sum", |
||||||
|
"type": "int256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPoolsToBeElected", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPoolsToBeRemoved", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "areStakeAndWithdrawAllowed", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "erc20TokenContract", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getCandidateMinStake", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getDelegatorMinStake", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isPoolActive", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "maxWithdrawAllowed", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "maxWithdrawOrderAllowed", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "onTokenTransfer", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "pure", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "orderedWithdrawAmount", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "orderedWithdrawAmountTotal", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "orderWithdrawEpoch", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakeAmountTotal", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolDelegators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_delegator", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolDelegatorIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_delegator", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolDelegatorInactiveIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolInactiveIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolToBeElectedIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "poolToBeRemovedIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakeAmount", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakeAmountByCurrentEpoch", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_staker", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakeAmountMinusOrderedWithdraw", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_poolStakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakeAmountTotalMinusOrderedWithdraw", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "stakingEpoch", |
||||||
|
"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" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,492 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "newValidatorSet", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "MAX_VALIDATORS", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "parentHash", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "newSet", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"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" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"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", |
||||||
|
"type": "function", |
||||||
|
"constant": false, |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "setStakingAddress", |
||||||
|
"type": "function", |
||||||
|
"constant": false, |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "banCounter", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "bannedUntil", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "blockRewardContract", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "changeRequestCount", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "emitInitiateChangeCallable", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPreviousValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPendingValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getQueueValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "initiateChangeAllowed", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isReportValidatorValid", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidator", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidatorOnPreviousEpoch", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidatorBanned", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "miningByStakingAddress", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "randomContract", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "stakingByMiningAddress", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "stakingContract", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "unremovableValidator", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "stakingAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "validatorCounter", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "validatorIndex", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "validatorSetApplyBlock", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,94 @@ |
|||||||
|
defmodule Explorer.Chain.Import.Runner.StakingPoolsTest do |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
alias Ecto.Multi |
||||||
|
alias Explorer.Chain.Import.Runner.StakingPools |
||||||
|
|
||||||
|
describe "run/1" do |
||||||
|
test "insert new pools list" do |
||||||
|
pools = [ |
||||||
|
%{ |
||||||
|
address_hash: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<11, 47, 94, 47, 60, 189, 134, 78, 170, 44, 100, 46, 55, 105, 193, 88, 35, 97, 202, 246>> |
||||||
|
}, |
||||||
|
metadata: %{ |
||||||
|
banned_unitil: 0, |
||||||
|
delegators_count: 0, |
||||||
|
is_active: true, |
||||||
|
is_banned: false, |
||||||
|
is_validator: true, |
||||||
|
mining_address: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<187, 202, 168, 212, 130, 137, 187, 31, 252, 249, 128, 141, 154, 164, 177, 210, 21, 5, 76, 120>> |
||||||
|
}, |
||||||
|
retries_count: 1, |
||||||
|
staked_amount: 0, |
||||||
|
was_banned_count: 0, |
||||||
|
was_validator_count: 1 |
||||||
|
}, |
||||||
|
name: "anonymous", |
||||||
|
primary: true |
||||||
|
}, |
||||||
|
%{ |
||||||
|
address_hash: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<170, 148, 182, 135, 211, 249, 85, 42, 69, 59, 129, 178, 131, 76, 165, 55, 120, 152, 13, 192>> |
||||||
|
}, |
||||||
|
metadata: %{ |
||||||
|
banned_unitil: 0, |
||||||
|
delegators_count: 0, |
||||||
|
is_active: true, |
||||||
|
is_banned: false, |
||||||
|
is_validator: true, |
||||||
|
mining_address: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<117, 223, 66, 56, 58, 254, 107, 245, 25, 74, 168, 250, 14, 155, 61, 95, 158, 134, 148, 65>> |
||||||
|
}, |
||||||
|
retries_count: 1, |
||||||
|
staked_amount: 0, |
||||||
|
was_banned_count: 0, |
||||||
|
was_validator_count: 1 |
||||||
|
}, |
||||||
|
name: "anonymous", |
||||||
|
primary: true |
||||||
|
}, |
||||||
|
%{ |
||||||
|
address_hash: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<49, 44, 35, 14, 125, 109, 176, 82, 36, 246, 2, 8, 166, 86, 227, 84, 28, 92, 66, 186>> |
||||||
|
}, |
||||||
|
metadata: %{ |
||||||
|
banned_unitil: 0, |
||||||
|
delegators_count: 0, |
||||||
|
is_active: true, |
||||||
|
is_banned: false, |
||||||
|
is_validator: true, |
||||||
|
mining_address: %Explorer.Chain.Hash{ |
||||||
|
byte_count: 20, |
||||||
|
bytes: <<82, 45, 243, 150, 174, 112, 160, 88, 189, 105, 119, 132, 8, 99, 15, 219, 2, 51, 137, 178>> |
||||||
|
}, |
||||||
|
retries_count: 1, |
||||||
|
staked_amount: 0, |
||||||
|
was_banned_count: 0, |
||||||
|
was_validator_count: 1 |
||||||
|
}, |
||||||
|
name: "anonymous", |
||||||
|
primary: true |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
assert {:ok, %{insert_staking_pools: list}} = run_changes(pools) |
||||||
|
assert Enum.count(list) == Enum.count(pools) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
defp run_changes(changes) do |
||||||
|
Multi.new() |
||||||
|
|> StakingPools.run(changes, %{ |
||||||
|
timeout: :infinity, |
||||||
|
timestamps: %{inserted_at: DateTime.utc_now(), updated_at: DateTime.utc_now()} |
||||||
|
}) |
||||||
|
|> Repo.transaction() |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,238 @@ |
|||||||
|
defmodule Explorer.Token.PoolsReaderTest do |
||||||
|
use EthereumJSONRPC.Case |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
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 = <<11, 47, 94, 47, 60, 189, 134, 78, 170, 44, 100, 46, 55, 105, 193, 88, 35, 97, 202, 246>> |
||||||
|
|
||||||
|
response = { |
||||||
|
:ok, |
||||||
|
%{ |
||||||
|
banned_until: 0, |
||||||
|
delegators_count: 0, |
||||||
|
is_active: true, |
||||||
|
is_banned: false, |
||||||
|
is_validator: true, |
||||||
|
mining_address: |
||||||
|
<<187, 202, 168, 212, 130, 137, 187, 31, 252, 249, 128, 141, 154, 164, 177, 210, 21, 5, 76, 120>>, |
||||||
|
staked_amount: 0, |
||||||
|
staking_address: <<11, 47, 94, 47, 60, 189, 134, 78, 170, 44, 100, 46, 55, 105, 193, 88, 35, 97, 202, 246>>, |
||||||
|
was_banned_count: 0, |
||||||
|
was_validator_count: 2 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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, |
||||||
|
2, |
||||||
|
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" |
||||||
|
} |
||||||
|
|
||||||
|
# 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 |
@ -0,0 +1,136 @@ |
|||||||
|
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.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: 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: 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, staking_address: address}, {failed, success} -> |
||||||
|
{[address | failed], success} |
||||||
|
|
||||||
|
pool, {failed, success} -> |
||||||
|
{failed, [changeset(pool) | success]} |
||||||
|
end) |
||||||
|
|
||||||
|
import_params = %{ |
||||||
|
staking_pools: %{params: 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 changeset(%{staking_address: staking_address} = pool) do |
||||||
|
{:ok, mining_address} = Chain.Hash.Address.cast(pool[:mining_address]) |
||||||
|
|
||||||
|
data = |
||||||
|
pool |
||||||
|
|> Map.delete(:staking_address) |
||||||
|
|> Map.put(:mining_address, mining_address) |
||||||
|
|
||||||
|
%{ |
||||||
|
name: "anonymous", |
||||||
|
primary: true, |
||||||
|
address_hash: staking_address, |
||||||
|
metadata: data |
||||||
|
} |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,205 @@ |
|||||||
|
defmodule Indexer.Fetcher.StakingPoolsTest do |
||||||
|
use EthereumJSONRPC.Case |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
import Mox |
||||||
|
|
||||||
|
alias Indexer.Fetcher.StakingPools |
||||||
|
alias Explorer.Staking.PoolsReader |
||||||
|
alias Explorer.Chain.Address |
||||||
|
|
||||||
|
@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) |
||||||
|
|
||||||
|
get_pool_data_from_blockchain() |
||||||
|
|
||||||
|
assert {:retry, retry_list} = StakingPools.run(list, nil) |
||||||
|
assert Enum.count(retry_list) == 2 |
||||||
|
|
||||||
|
pool = Explorer.Repo.get_by(Address.Name, address_hash: success_address) |
||||||
|
assert pool.name == "anonymous" |
||||||
|
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" |
||||||
|
} |
||||||
|
|
||||||
|
# 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 |
Loading…
Reference in new issue