Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test to fail suite if event map doesn't cover all the events in the application #594

Merged
merged 3 commits into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ defmodule Explorer.Celo.ContractEvents.EventMap do
Elixir.Explorer.Celo.ContractEvents.Election.EpochRewardsDistributedToVotersEvent,
"0xe5d4e30fb8364e57bc4d662a07d0cf36f4c34552004c4c3624620a2c1d1c03dc" =>
Elixir.Explorer.Celo.ContractEvents.Goldtoken.TransferCommentEvent,
"0xe5d4e30fb8364e57bc4d662a07d0cf36f4c34552004c4c3624620a2c1d1c03dc" =>
Elixir.Explorer.Celo.ContractEvents.Stabletoken.TransferCommentEvent,
"0xae7458f8697a680da6be36406ea0b8f40164915ac9cc40c0dad05a2ff6e8c6a8" =>
Elixir.Explorer.Celo.ContractEvents.Election.ValidatorGroupActiveVoteRevokedEvent,
"0xd3532f70444893db82221041edb4dc26c94593aeb364b0b14dfc77d5ee905152" =>
Expand All @@ -82,23 +80,6 @@ defmodule Explorer.Celo.ContractEvents.EventMap do
Elixir.Explorer.Celo.ContractEvents.Validators.ValidatorEcdsaPublicKeyUpdatedEvent
}

@name_to_event %{
"ValidatorGroupVoteActivated" => Elixir.Explorer.Celo.ContractEvents.Election.ValidatorGroupVoteActivatedEvent,
"ConstitutionSet" => Elixir.Explorer.Celo.ContractEvents.Governance.ConstitutionSetEvent,
"AssetAllocationSet" => Elixir.Explorer.Celo.ContractEvents.Reserve.AssetAllocationSetEvent,
"EpochRewardsDistributedToVoters" =>
Elixir.Explorer.Celo.ContractEvents.Election.EpochRewardsDistributedToVotersEvent,
"TransferComment" => Elixir.Explorer.Celo.ContractEvents.Goldtoken.TransferCommentEvent,
"TransferComment" => Elixir.Explorer.Celo.ContractEvents.Stabletoken.TransferCommentEvent,
"ValidatorGroupActiveVoteRevoked" =>
Elixir.Explorer.Celo.ContractEvents.Election.ValidatorGroupActiveVoteRevokedEvent,
"ValidatorGroupVoteCast" => Elixir.Explorer.Celo.ContractEvents.Election.ValidatorGroupVoteCastEvent,
"ValidatorEpochPaymentDistributed" =>
Elixir.Explorer.Celo.ContractEvents.Validators.ValidatorEpochPaymentDistributedEvent,
"ValidatorEcdsaPublicKeyUpdated" =>
Elixir.Explorer.Celo.ContractEvents.Validators.ValidatorEcdsaPublicKeyUpdatedEvent
}

def event_for_topic(topic), do: Map.get(@topic_to_event, topic)
def maps, do: {@name_to_event, @topic_to_event}
def map, do: @topic_to_event
end
83 changes: 7 additions & 76 deletions apps/explorer/lib/mix/tasks/event_map.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,96 +4,27 @@ defmodule Mix.Tasks.EventMap do
use Mix.Task

alias Explorer.Celo.ContractEvents.EventTransformer

@template """
# This file is auto generated, changes will be lost upon regeneration

defmodule Explorer.Celo.ContractEvents.EventMap do
@moduledoc "Map event names and event topics to concrete contract event structs"

alias Explorer.Celo.ContractEvents.EventTransformer
alias Explorer.Repo

@doc "Convert ethrpc log parameters to CeloContractEvent insertion parameters"
def rpc_to_event_params(logs) when is_list(logs) do
logs
|> Enum.map(fn params = %{first_topic: event_topic} ->
case event_for_topic(event_topic) do
nil ->
nil

event ->
event
|> struct!()
|> EventTransformer.from_params(params)
|> EventTransformer.to_celo_contract_event_params()
end
end)
|> Enum.reject(&is_nil/1)
end

@doc "Convert CeloContractEvent instance to their concrete types"
def celo_contract_event_to_concrete_event(events) when is_list(events) do
events
|> Enum.map(&celo_contract_event_to_concrete_event/1)
|> Enum.reject(&is_nil/1)
end

def celo_contract_event_to_concrete_event(%{topic: topic} = params) do
case event_for_topic(topic) do
nil ->
nil

event ->
event
|> struct!()
|> EventTransformer.from_celo_contract_event(params)
end
end

@doc "Run ecto query and convert all CeloContractEvents into their concrete types"
def query_all(query) do
query
|> Repo.all()
|> celo_contract_event_to_concrete_event()
end

@doc "Convert concrete event to CeloContractEvent insertion parameters"
def event_to_contract_event_params(events) when is_list(events) do
events |> Enum.map(&event_to_contract_event_params/1)
end

def event_to_contract_event_params(event) do
event |> EventTransformer.to_celo_contract_event_params()
end

@topic_to_event %{
<%= for module <- @modules do %> "<%= module.topic %>" =>
<%= module %>,
<% end %>}

def event_for_topic(topic), do: Map.get(@topic_to_event, topic)
def map, do: @topic_to_event

end

"""
require Logger

@path "lib/explorer/celo/events/contract_events/event_map.ex"

@template "lib/explorer/mix.tasks/event_map_template.eex"
@shortdoc "Creates a module mapping topics to event names and vice versa"
def run(args) do
{options, _, _} = OptionParser.parse(args, strict: [verbose: :boolean])

modules = get_events()
event_map = EEx.eval_string(@template, assigns: [modules: modules])

Logger.info("Found #{length(modules)} Celo contract events defined in the Explorer application")
event_map = EEx.eval_file(@template, assigns: [modules: modules])

if Keyword.get(options, :verbose) do
IO.puts(event_map)
end

_ = File.rm(@path)
File.write(@path, event_map)

Logger.info("Wrote event map to #{@path}")
end

@dialyzer {:nowarn_function, get_events: 0}
Expand Down
68 changes: 68 additions & 0 deletions apps/explorer/lib/mix/tasks/event_map_template.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# This file is auto generated, changes will be lost upon regeneration
defmodule Explorer.Celo.ContractEvents.EventMap do
@moduledoc "Map event names and event topics to concrete contract event structs"

alias Explorer.Celo.ContractEvents.EventTransformer
alias Explorer.Repo

@doc "Convert ethrpc log parameters to CeloContractEvent insertion parameters"
def rpc_to_event_params(logs) when is_list(logs) do
logs
|> Enum.map(fn params = %{first_topic: event_topic} ->
case event_for_topic(event_topic) do
nil ->
nil

event ->
event
|> struct!()
|> EventTransformer.from_params(params)
|> EventTransformer.to_celo_contract_event_params()
end
end)
|> Enum.reject(&is_nil/1)
end

@doc "Convert CeloContractEvent instance to their concrete types"
def celo_contract_event_to_concrete_event(events) when is_list(events) do
events
|> Enum.map(&celo_contract_event_to_concrete_event/1)
|> Enum.reject(&is_nil/1)
end

def celo_contract_event_to_concrete_event(%{topic: topic} = params) do
case event_for_topic(topic) do
nil ->
nil

event ->
event
|> struct!()
|> EventTransformer.from_celo_contract_event(params)
end
end

@doc "Run ecto query and convert all CeloContractEvents into their concrete types"
def query_all(query) do
query
|> Repo.all()
|> celo_contract_event_to_concrete_event()
end

@doc "Convert concrete event to CeloContractEvent insertion parameters"
def event_to_contract_event_params(events) when is_list(events) do
events |> Enum.map(&event_to_contract_event_params/1)
end

def event_to_contract_event_params(event) do
event |> EventTransformer.to_celo_contract_event_params()
end

@topic_to_event %{
<%= for module <- @modules do %> "<%= module.topic %>" =>
<%= module %>,
<% end %>}

def event_for_topic(topic), do: Map.get(@topic_to_event, topic)
def map, do: @topic_to_event
end
14 changes: 14 additions & 0 deletions apps/explorer/test/explorer/celo/events/event_map_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Explorer.Celo.ContractEvents.EventMapTest do

alias Explorer.Celo.ContractEvents.Election.ValidatorGroupActiveVoteRevokedEvent
alias Explorer.Celo.ContractEvents.EventMap
alias Explorer.Celo.ContractEvents.EventTransformer
alias Explorer.Repo

describe "event map" do
Expand Down Expand Up @@ -78,4 +79,17 @@ defmodule Explorer.Celo.ContractEvents.EventMapTest do
assert result.value == 420_420_420
end
end

describe "General functionality" do
test "event map should have definitions for all events" do
event_map_topic_set = EventMap.map() |> Map.keys() |> MapSet.new()

contract_events_topic_set =
EventTransformer.__protocol__(:impls)
|> then(fn {:consolidated, modules} -> Enum.map(modules, & &1.topic()) end)
|> MapSet.new()

assert MapSet.subset?(contract_events_topic_set, event_map_topic_set)
end
end
end