Merge pull request #1240 from poanetwork/gsf-validator-metadata
validator metadata retrieval and displaypull/1252/head
commit
cabee38387
@ -0,0 +1,41 @@ |
|||||||
|
<div class="modal fade" id="validatorModal" tabindex="-1" role="dialog" aria-labelledby="validatorModalLabel" aria-hidden="true"> |
||||||
|
<div class="modal-dialog modal-md" role="document"> |
||||||
|
<div class="modal-content"> |
||||||
|
<div class="modal-header"> |
||||||
|
<h2 class="modal-title" id="validatorModalLabel"><%= gettext"Validator Data" %></h2> |
||||||
|
</div> |
||||||
|
<div class="modal-body"> |
||||||
|
<h1 class="text-center"><%= @address_name %></h1> |
||||||
|
<div class="row mt-2"> |
||||||
|
<div class="col-sm-4 text-right text-muted"><%= gettext"License ID" %></div> |
||||||
|
<div class="col-sm-8"> |
||||||
|
<%= @validator_metadata["license_id"] %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="row mt-2"> |
||||||
|
<div class="col-sm-4 text-right text-muted"><%= gettext"Address" %></div> |
||||||
|
<div class="col-sm-8"> |
||||||
|
<%= @validator_metadata["address"] %>, |
||||||
|
<%= @validator_metadata["state"] %>, |
||||||
|
<%= @validator_metadata["zipcode"] %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="row mt-2"> |
||||||
|
<div class="col-sm-4 text-right text-muted"><%= gettext"License Expires" %></div> |
||||||
|
<div class="col-sm-8"> |
||||||
|
<%= format_datetime_string(@validator_metadata["expiration_date"]) %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="row mt-2"> |
||||||
|
<div class="col-sm-4 text-right text-muted"><%= gettext"Validator Creation Date" %></div> |
||||||
|
<div class="col-sm-8"> |
||||||
|
<%= format_datetime_string(@validator_metadata["created_date"]) %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="modal-footer"> |
||||||
|
<button type="button" class="btn btn-primary" data-dismiss="modal"><%= gettext "Close" %></button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
@ -0,0 +1,36 @@ |
|||||||
|
defmodule Explorer.Validator.MetadataImporter do |
||||||
|
@moduledoc """ |
||||||
|
module that upserts validator metadata from a list of maps |
||||||
|
""" |
||||||
|
alias Explorer.Chain.Address |
||||||
|
alias Explorer.Repo |
||||||
|
|
||||||
|
import Ecto.Query, only: [from: 2] |
||||||
|
|
||||||
|
def import_metadata(metadata_maps) do |
||||||
|
Repo.transaction(fn -> Enum.each(metadata_maps, &upsert_validator_metadata(&1)) end) |
||||||
|
end |
||||||
|
|
||||||
|
defp upsert_validator_metadata(validator_changeset) do |
||||||
|
case Repo.get_by(Address.Name, address_hash: validator_changeset.address_hash, primary: true) do |
||||||
|
nil -> |
||||||
|
%Address.Name{} |
||||||
|
|> Address.Name.changeset(validator_changeset) |
||||||
|
|> Repo.insert() |
||||||
|
|
||||||
|
_address_name -> |
||||||
|
query = |
||||||
|
from(an in Address.Name, |
||||||
|
update: [ |
||||||
|
set: [ |
||||||
|
name: ^validator_changeset.name, |
||||||
|
metadata: ^validator_changeset.metadata |
||||||
|
] |
||||||
|
], |
||||||
|
where: an.address_hash == ^validator_changeset.address_hash and an.primary == true |
||||||
|
) |
||||||
|
|
||||||
|
Repo.update_all(query, []) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,31 @@ |
|||||||
|
defmodule Explorer.Validator.MetadataProcessor do |
||||||
|
@moduledoc """ |
||||||
|
module to periodically retrieve and update metadata belonging to validators |
||||||
|
""" |
||||||
|
use GenServer |
||||||
|
alias Explorer.Validator.{MetadataImporter, MetadataRetriever} |
||||||
|
|
||||||
|
def start_link(_) do |
||||||
|
GenServer.start_link(__MODULE__, :ok, name: __MODULE__) |
||||||
|
end |
||||||
|
|
||||||
|
@impl true |
||||||
|
def init(args) do |
||||||
|
send(self(), :import_and_reschedule) |
||||||
|
{:ok, args} |
||||||
|
end |
||||||
|
|
||||||
|
@impl true |
||||||
|
def handle_info(:import_and_reschedule, state) do |
||||||
|
MetadataRetriever.fetch_data() |
||||||
|
|> MetadataImporter.import_metadata() |
||||||
|
|
||||||
|
reschedule() |
||||||
|
|
||||||
|
{:noreply, state} |
||||||
|
end |
||||||
|
|
||||||
|
defp reschedule do |
||||||
|
Process.send_after(self(), :import_and_reschedule, :timer.hours(24)) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,76 @@ |
|||||||
|
defmodule Explorer.Validator.MetadataRetriever do |
||||||
|
@moduledoc """ |
||||||
|
Consults the configured smart contracts to fetch the valivators' metadata |
||||||
|
""" |
||||||
|
|
||||||
|
alias Explorer.SmartContract.Reader |
||||||
|
|
||||||
|
def fetch_data do |
||||||
|
fetch_validators_list() |
||||||
|
|> Enum.map(fn validator -> |
||||||
|
validator |
||||||
|
|> fetch_validator_metadata |
||||||
|
|> translate_metadata |
||||||
|
|> Map.merge(%{address_hash: validator, primary: true}) |
||||||
|
end) |
||||||
|
end |
||||||
|
|
||||||
|
defp fetch_validators_list do |
||||||
|
%{"getValidators" => {:ok, [validators]}} = |
||||||
|
Reader.query_contract(config(:validators_contract_address), contract_abi("validators.json"), %{ |
||||||
|
"getValidators" => [] |
||||||
|
}) |
||||||
|
|
||||||
|
validators |
||||||
|
end |
||||||
|
|
||||||
|
defp fetch_validator_metadata(validator_address) do |
||||||
|
%{"validators" => {:ok, fields}} = |
||||||
|
Reader.query_contract(config(:metadata_contract_address), contract_abi("metadata.json"), %{ |
||||||
|
"validators" => [validator_address] |
||||||
|
}) |
||||||
|
|
||||||
|
fields |
||||||
|
end |
||||||
|
|
||||||
|
defp translate_metadata([ |
||||||
|
first_name, |
||||||
|
last_name, |
||||||
|
license_id, |
||||||
|
full_address, |
||||||
|
state, |
||||||
|
zipcode, |
||||||
|
expiration_date, |
||||||
|
created_date, |
||||||
|
_updated_date, |
||||||
|
_min_treshold |
||||||
|
]) do |
||||||
|
%{ |
||||||
|
name: trim_null_bytes(first_name) <> " " <> trim_null_bytes(last_name), |
||||||
|
metadata: %{ |
||||||
|
license_id: trim_null_bytes(license_id), |
||||||
|
address: full_address, |
||||||
|
state: trim_null_bytes(state), |
||||||
|
zipcode: trim_null_bytes(zipcode), |
||||||
|
expiration_date: expiration_date, |
||||||
|
created_date: created_date |
||||||
|
} |
||||||
|
} |
||||||
|
end |
||||||
|
|
||||||
|
defp trim_null_bytes(bytes) do |
||||||
|
String.trim_trailing(bytes, <<0>>) |
||||||
|
end |
||||||
|
|
||||||
|
defp config(key) do |
||||||
|
Application.get_env(:explorer, __MODULE__, [])[key] |
||||||
|
end |
||||||
|
|
||||||
|
# sobelow_skip ["Traversal"] |
||||||
|
defp contract_abi(file_name) do |
||||||
|
:explorer |
||||||
|
|> Application.app_dir("priv/validator_contracts_abi/#{file_name}") |
||||||
|
|> File.read!() |
||||||
|
|> Jason.decode!() |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,9 @@ |
|||||||
|
defmodule Explorer.Repo.Migrations.AddMetadataFieldToAddressNames do |
||||||
|
use Ecto.Migration |
||||||
|
|
||||||
|
def change do |
||||||
|
alter table(:address_names) do |
||||||
|
add(:metadata, :map) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,579 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "pendingChanges", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "lastName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "licenseId", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "fullAddress", |
||||||
|
"type": "string" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "state", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "zipcode", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "expirationDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "createdDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "updatedDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "minThreshold", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x022c254a" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_lastName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_licenseId", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_fullAddress", |
||||||
|
"type": "string" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_state", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_zipcode", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_expirationDate", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "createMetadata", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x334460a4" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "confirmations", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "count", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "voters", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x4ecb35c4" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "finalize", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x4ef39b75" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getTime", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x557ed1ba" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "clearMetadata", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x885c69b5" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_lastName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_licenseId", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_fullAddress", |
||||||
|
"type": "string" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_state", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_zipcode", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_expirationDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_createdDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_updatedDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_minThreshold", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "initMetadata", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x8ae881a6" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "confirmPendingChange", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x9c715535" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "initMetadataDisabled", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xa6662a3c" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "proxyStorage", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xae4b1b5b" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "getValidatorName", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "lastName", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xaf2e2da9" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_oldMiningKey", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_newMiningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "moveMetadata", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xc2d0916f" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_lastName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_licenseId", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_fullAddress", |
||||||
|
"type": "string" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_state", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_zipcode", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_expirationDate", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "changeRequest", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xc3f1b0ea" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getMinThreshold", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xe6bbe9dd" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "initMetadataDisable", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xf0174a25" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_voterMiningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidatorAlreadyVoted", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xf73294b8" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "cancelPendingChange", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xf94c12cb" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "validators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "firstName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "lastName", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "licenseId", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "fullAddress", |
||||||
|
"type": "string" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "state", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "zipcode", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "expirationDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "createdDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "updatedDate", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "minThreshold", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xfa52c7d8" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "MetadataCleared", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x1928e25e316bab82325e01eaf5b4a29f7b2d5e3d77fc0b6ac959eb95112f3ee9" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "MetadataCreated", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x76a10cc0839d166c55eec8dba39ff22f75470574ede5014b744b45cebea5fc7e" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "oldMiningKey", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "newMiningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "MetadataMoved", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x6a3e5f5cc14de86bb3be87bc976b74890ecd0c8fa0cfca2fe3fefe55c9b47dde" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "ChangeRequestInitiated", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x6ec0e3afd4b29a1fe1c688cb1e6474d9e2c6a1032858c3add0ff32b7ba95f32f" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "CancelledRequest", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x5a1dcc05b2a41ad121a798e749b9ba9584177c68a4047ee52ef37d4ca76ce08c" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "votingSender", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "votingSenderMiningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "Confirmed", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x603c57ecb4a9802537649ceb6523e5d48c939e7856768ce6f9b3128a889a5cfe" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "miningKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "FinalizedChange", |
||||||
|
"type": "event", |
||||||
|
"signature": "0xccf0f685803f0fba33ec88246b35d75b758b1e77c3d65ef5658f7e630f36b85b" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,462 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "pendingList", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x03aca792" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getCurrentValidatorsLength", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x0eaba26a" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_newAddress", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "setProxyStorage", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x10855269" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_validator", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_shouldFireEvent", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "addValidator", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x21a3fb85" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "isMasterOfCeremonyRemovedPending", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x273cb593" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "isMasterOfCeremonyRemoved", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x379fed9a" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "validatorsState", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "isValidator", |
||||||
|
"type": "bool" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "isValidatorFinalized", |
||||||
|
"type": "bool" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "index", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x4110a489" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getPendingList", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x45199e0a" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "finalizeChange", |
||||||
|
"outputs": [], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x75286211" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_newKey", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_oldKey", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "swapValidatorKey", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x879736b2" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_someone", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidatorFinalized", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x8f2eabe1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "currentValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x900eb5a8" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getKeysManager", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0x9a573786" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "wasProxyStorageSet", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xa5f8b874" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getCurrentValidatorsLengthWithoutMoC", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xa8756337" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "proxyStorage", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xae4b1b5b" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "finalized", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xb3f05b97" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "getValidators", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xb7ab4db5" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "systemAddress", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xd3e848f1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "masterOfCeremonyPending", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xec7de1e9" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_validator", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "_shouldFireEvent", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "removeValidator", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xf89a77b1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [], |
||||||
|
"name": "masterOfCeremony", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xfa81b200" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"constant": true, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_someone", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "isValidator", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function", |
||||||
|
"signature": "0xfacd743b" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"name": "_masterOfCeremony", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "validators", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"payable": false, |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "constructor", |
||||||
|
"signature": "constructor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"name": "parentHash", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "newSet", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "InitiateChange", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "newSet", |
||||||
|
"type": "address[]" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "ChangeFinalized", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x8564cd629b15f47dc310d45bcbfc9bcf5420b0d51bf0659a16c67f91d2763253" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"name": "proxyStorage", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "MoCInitializedProxyStorage", |
||||||
|
"type": "event", |
||||||
|
"signature": "0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,48 @@ |
|||||||
|
defmodule Explorer.Validator.MetadataImporterTest do |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
require Ecto.Query |
||||||
|
|
||||||
|
import Ecto.Query |
||||||
|
import Explorer.Factory |
||||||
|
|
||||||
|
alias Explorer.Chain.Address |
||||||
|
alias Explorer.Repo |
||||||
|
alias Explorer.Validator.MetadataImporter |
||||||
|
|
||||||
|
describe "import_metadata/1" do |
||||||
|
test "inserts new address names when there's none for the validators" do |
||||||
|
address = insert(:address) |
||||||
|
|
||||||
|
[%{address_hash: address.hash, name: "Testinit Unitorius", primary: true, metadata: %{"test" => "toast"}}] |
||||||
|
|> MetadataImporter.import_metadata() |
||||||
|
|
||||||
|
address_names = |
||||||
|
from(an in Address.Name, where: an.address_hash == ^address.hash and an.primary == true) |
||||||
|
|> Repo.all() |
||||||
|
|
||||||
|
expected_name = %Address.Name{address_hash: address.hash, name: "Testit Unitorus", metadata: %{"test" => "toast"}} |
||||||
|
|
||||||
|
assert length(address_names) == 1 |
||||||
|
assert expected_name = hd(address_names) |
||||||
|
end |
||||||
|
|
||||||
|
test "updates the primary address name if the validator already has one" do |
||||||
|
address = insert(:address) |
||||||
|
|
||||||
|
insert(:address_name, address: address, primary: true, name: "Nodealus Faileddi") |
||||||
|
|
||||||
|
[%{address_hash: address.hash, name: "Testit Unitorus", primary: true, metadata: %{"test" => "toast"}}] |
||||||
|
|> MetadataImporter.import_metadata() |
||||||
|
|
||||||
|
address_names = |
||||||
|
from(an in Address.Name, where: an.address_hash == ^address.hash and an.primary == true) |
||||||
|
|> Repo.all() |
||||||
|
|
||||||
|
expected_name = %Address.Name{address_hash: address.hash, name: "Testit Unitorus", metadata: %{"test" => "toast"}} |
||||||
|
|
||||||
|
assert length(address_names) == 1 |
||||||
|
assert expected_name = hd(address_names) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,100 @@ |
|||||||
|
defmodule Explorer.Validator.MetadataRetrieverTest do |
||||||
|
use EthereumJSONRPC.Case |
||||||
|
|
||||||
|
alias Explorer.Validator.MetadataRetriever |
||||||
|
import Mox |
||||||
|
|
||||||
|
setup :verify_on_exit! |
||||||
|
setup :set_mox_global |
||||||
|
|
||||||
|
describe "fetch_data/0" do |
||||||
|
test "returns maps with the info on each validator" do |
||||||
|
validators_list_mox_ok() |
||||||
|
validator_metadata_mox_ok() |
||||||
|
|
||||||
|
expected = [ |
||||||
|
%{ |
||||||
|
address_hash: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>, |
||||||
|
name: "Testname Unitarion", |
||||||
|
primary: true, |
||||||
|
metadata: %{ |
||||||
|
address: "", |
||||||
|
created_date: 0, |
||||||
|
expiration_date: 253_370_764_800, |
||||||
|
license_id: "00000000", |
||||||
|
state: "XX", |
||||||
|
zipcode: "00000" |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
assert MetadataRetriever.fetch_data() == expected |
||||||
|
end |
||||||
|
|
||||||
|
test "raise error when the first contract call fails" do |
||||||
|
contract_request_with_error("getValidators") |
||||||
|
assert_raise(MatchError, fn -> MetadataRetriever.fetch_data() end) |
||||||
|
end |
||||||
|
|
||||||
|
test "raise error when a call to the metadatc contract fails" do |
||||||
|
validators_list_mox_ok() |
||||||
|
contract_request_with_error("validators") |
||||||
|
assert_raise(MatchError, fn -> MetadataRetriever.fetch_data() end) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
defp contract_request_with_error(id) do |
||||||
|
expect( |
||||||
|
EthereumJSONRPC.Mox, |
||||||
|
:json_rpc, |
||||||
|
fn [%{id: id, method: _, params: _}], _options -> |
||||||
|
{:ok, |
||||||
|
[ |
||||||
|
%{ |
||||||
|
error: %{code: -32015, data: "Reverted 0x", message: "VM execution error."}, |
||||||
|
id: id, |
||||||
|
jsonrpc: "2.0" |
||||||
|
} |
||||||
|
]} |
||||||
|
end |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
defp validators_list_mox_ok() do |
||||||
|
expect( |
||||||
|
EthereumJSONRPC.Mox, |
||||||
|
:json_rpc, |
||||||
|
1, |
||||||
|
fn [%{id: "getValidators"}], _opts -> |
||||||
|
{:ok, |
||||||
|
[ |
||||||
|
%{ |
||||||
|
id: "getValidators", |
||||||
|
jsonrpc: "2.0", |
||||||
|
result: |
||||||
|
"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001" |
||||||
|
} |
||||||
|
]} |
||||||
|
end |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
defp validator_metadata_mox_ok() do |
||||||
|
expect( |
||||||
|
EthereumJSONRPC.Mox, |
||||||
|
:json_rpc, |
||||||
|
1, |
||||||
|
fn [%{id: "validators"}], _opts -> |
||||||
|
{:ok, |
||||||
|
[ |
||||||
|
%{ |
||||||
|
id: "validators", |
||||||
|
jsonrpc: "2.0", |
||||||
|
result: |
||||||
|
"0x546573746e616d65000000000000000000000000000000000000000000000000556e69746172696f6e000000000000000000000000000000000000000000000030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140585800000000000000000000000000000000000000000000000000000000000030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003afe130e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058585858585858207374726565742058585858585800000000000000000000000000000000000000000000000000000000000000000000000000000000000000" |
||||||
|
} |
||||||
|
]} |
||||||
|
end |
||||||
|
) |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue