Skip to content

Commit

Permalink
Add test to fail suite if event map doesn't cover all the events in t…
Browse files Browse the repository at this point in the history
…he application (#594)

* Generate event map + add test.

* Move event map template to external file.

* Regenerate map.
  • Loading branch information
rkachowski authored Mar 23, 2022
1 parent 2796401 commit ea9c730
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 96 deletions.
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

0 comments on commit ea9c730

Please sign in to comment.