From f7436128770f07529680cb003cbf0c1c182d30b1 Mon Sep 17 00:00:00 2001 From: Sebastian Borrazas Date: Wed, 4 Jan 2023 08:21:51 -0300 Subject: [PATCH] feat: add block hash to activities (#1098) --- lib/ae_mdw/activities.ex | 120 +++++++++++------- .../activities_controller_test.exs | 99 ++++++++++++++- 2 files changed, 170 insertions(+), 49 deletions(-) diff --git a/lib/ae_mdw/activities.ex b/lib/ae_mdw/activities.ex index 6d380b8b7..f74c7cea4 100644 --- a/lib/ae_mdw/activities.ex +++ b/lib/ae_mdw/activities.ex @@ -42,6 +42,7 @@ defmodule AeMdw.Activities do non_neg_integer()} | {:int_transfer, IntTransfer.kind(), Txs.txi()} | :claim + @typep activity_type() :: String.t() @max_pos 4 @min_int Util.min_int() @@ -165,15 +166,47 @@ defmodule AeMdw.Activities do end |> Collection.paginate(pagination) - events = - Enum.map(activities_locators_data, fn {{height, txi, _local_idx}, data} -> - render(state, account_pk, height, txi, data) - end) + events = render_activities(state, account_pk, activities_locators_data) {:ok, serialize_cursor(prev_cursor), events, serialize_cursor(next_cursor)} end end + defp render_activities(state, account_pk, activities_locators_data) do + {activities_locators_data, _acc} = + Enum.map_reduce(activities_locators_data, nil, fn + {{_height, txi, _local_idx}, _data} = locator, {:txi, txi, enc_mb_hash} = block_info -> + {{enc_mb_hash, locator}, block_info} + + {{height, -1, _local_idx}, _data} = locator, {:gen, height, enc_kb_hash} = block_info -> + {{enc_kb_hash, locator}, block_info} + + {{height, -1, _local_idx}, _data} = locator, _block_info -> + Model.block(hash: kb_hash) = State.fetch!(state, Model.Block, {height, -1}) + enc_kb_hash = Enc.encode(:key_block_hash, kb_hash) + + {{enc_kb_hash, locator}, {:gen, height, enc_kb_hash}} + + {{_height, txi, _local_idx}, _data} = locator, _block_info -> + Model.tx(block_index: block_index) = State.fetch!(state, Model.Tx, txi) + Model.block(hash: kb_hash) = State.fetch!(state, Model.Block, block_index) + enc_mb_hash = Enc.encode(:micro_block_hash, kb_hash) + + {{enc_mb_hash, locator}, {:txi, txi, enc_mb_hash}} + end) + + Enum.map(activities_locators_data, fn {block_hash, {{height, txi, _local_idx}, data}} -> + {type, payload} = render_payload(state, account_pk, height, txi, data) + + %{ + height: height, + block_hash: block_hash, + type: type, + payload: payload + } + end) + end + defp build_name_claims_stream(state, direction, name_hash, txi_scope, txi_cursor) do with {:ok, Model.plain_name(value: plain_name)} <- State.get(state, Model.PlainName, name_hash), @@ -458,18 +491,15 @@ defmodule AeMdw.Activities do end) end - @spec render(state(), Db.pubkey(), height(), txi(), activity_value()) :: map() - defp render(state, _account_pk, height, txi, {:field, tx_type, _tx_pos}) do + @spec render_payload(state(), Db.pubkey(), height(), txi(), activity_value()) :: + {activity_type(), map()} + defp render_payload(state, _account_pk, _height, txi, {:field, tx_type, _tx_pos}) do tx = state |> Txs.fetch!(txi) |> Map.delete("tx_index") - %{ - height: height, - type: "#{Node.tx_name(tx_type)}Event", - payload: tx - } + {"#{Node.tx_name(tx_type)}Event", tx} end - defp render(state, account_pk, height, txi, :claim) do + defp render_payload(state, account_pk, _height, txi, :claim) do Model.tx(id: tx_hash, time: micro_time) = State.fetch!(state, Model.Tx, txi) claim_aetx = @@ -479,48 +509,46 @@ defmodule AeMdw.Activities do name_hash == account_pk end) - %{ - height: height, - type: "NameClaimEvent", - payload: %{ - micro_time: micro_time, - tx_hash: Enc.encode(:tx_hash, tx_hash), - tx: :aetx.serialize_for_client(claim_aetx) - } + payload = %{ + micro_time: micro_time, + tx_hash: Enc.encode(:tx_hash, tx_hash), + tx: :aetx.serialize_for_client(claim_aetx) } + + {"NameClaimEvent", payload} end - defp render(state, _account_pk, height, call_txi, {:int_contract_call, local_idx}) do + defp render_payload(state, _account_pk, _height, call_txi, {:int_contract_call, local_idx}) do payload = state |> Format.to_map({call_txi, local_idx}, Model.IntContractCall) |> Map.drop([:call_txi, :create_txi]) - %{ - height: height, - type: "InternalContractCallEvent", - payload: payload - } + {"InternalContractCallEvent", payload} end - defp render(state, account_pk, height, txi, {:int_transfer, kind, ref_txi}) do + defp render_payload(state, account_pk, height, txi, {:int_transfer, kind, ref_txi}) do transfer_key = {{height, txi}, kind, account_pk, ref_txi} m_transfer = State.fetch!(state, Model.IntTransferTx, transfer_key) amount = Model.int_transfer_tx(m_transfer, :amount) ref_tx_hash = if ref_txi >= 0, do: Enc.encode(:tx_hash, Txs.txi_to_hash(state, ref_txi)) - %{ - height: height, - type: "InternalTransferEvent", - payload: %{ - amount: amount, - kind: kind, - ref_tx_hash: ref_tx_hash - } + payload = %{ + amount: amount, + kind: kind, + ref_tx_hash: ref_tx_hash } + + {"InternalTransferEvent", payload} end - defp render(state, _account_pk, height, txi, {:aexn, :aex9, from_pk, to_pk, value, index}) do + defp render_payload( + state, + _account_pk, + _height, + txi, + {:aexn, :aex9, from_pk, to_pk, value, index} + ) do payload = state |> AexnView.sender_transfer_to_map({:aex9, from_pk, txi, to_pk, value, index}) @@ -528,14 +556,16 @@ defmodule AeMdw.Activities do |> Util.map_rename(:sender, :sender_id) |> Util.map_rename(:recipient, :recipient_id) - %{ - height: height, - type: "Aex9TransferEvent", - payload: payload - } + {"Aex9TransferEvent", payload} end - defp render(state, _account_pk, height, txi, {:aexn, :aex141, from_pk, to_pk, value, index}) do + defp render_payload( + state, + _account_pk, + _height, + txi, + {:aexn, :aex141, from_pk, to_pk, value, index} + ) do payload = state |> AexnView.sender_transfer_to_map({:aex141, from_pk, txi, to_pk, value, index}) @@ -543,11 +573,7 @@ defmodule AeMdw.Activities do |> Util.map_rename(:sender, :sender_id) |> Util.map_rename(:recipient, :recipient_id) - %{ - height: height, - type: "Aex141TransferEvent", - payload: payload - } + {"Aex141TransferEvent", payload} end defp serialize_cursor(nil), do: nil diff --git a/test/ae_mdw_web/controllers/activities_controller_test.exs b/test/ae_mdw_web/controllers/activities_controller_test.exs index dec40f712..1abf6769e 100644 --- a/test/ae_mdw_web/controllers/activities_controller_test.exs +++ b/test/ae_mdw_web/controllers/activities_controller_test.exs @@ -23,6 +23,9 @@ defmodule AeMdwWeb.ActivitiesControllerTest do account_id = :aeser_id.create(:account, account_pk) height = 398 mbi = 2 + kb_hash = TS.key_block_hash(0) + mb_hash = TS.micro_block_hash(0) + enc_mb_hash = Enc.encode(:micro_block_hash, mb_hash) {:ok, aetx} = :aec_spend_tx.new(%{ @@ -48,6 +51,8 @@ defmodule AeMdwWeb.ActivitiesControllerTest do Model.Field, Model.field(index: {:contract_create_tx, nil, next_account_pk, 4}) ) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash)) + |> Store.put(Model.Block, Model.block(index: {height, mbi}, hash: mb_hash)) with_mocks [ {Db, [], @@ -67,18 +72,21 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "ContractCallTxEvent", "payload" => %{"micro_index" => ^mbi} } = tx1 assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "ContractCallTxEvent", "payload" => %{"micro_index" => ^mbi} } = tx2 assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "ContractCallTxEvent", "payload" => %{"micro_index" => ^mbi} } = tx3 @@ -92,6 +100,9 @@ defmodule AeMdwWeb.ActivitiesControllerTest do account_id = :aeser_id.create(:account, account_pk) height = 398 mbi = 2 + kb_hash = TS.key_block_hash(0) + mb_hash = TS.micro_block_hash(0) + enc_mb_hash = Enc.encode(:micro_block_hash, mb_hash) {:ok, aetx} = :aec_spend_tx.new(%{ @@ -113,6 +124,8 @@ defmodule AeMdwWeb.ActivitiesControllerTest do |> Store.put(Model.Tx, Model.tx(index: 2, block_index: {height, mbi}, id: "hash2")) |> Store.put(Model.Field, Model.field(index: {:contract_call_tx, 1, account_pk, 3})) |> Store.put(Model.Tx, Model.tx(index: 3, block_index: {height, mbi}, id: "hash3")) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash)) + |> Store.put(Model.Block, Model.block(index: {height, mbi}, hash: mb_hash)) with_mocks [ {Db, [], @@ -136,12 +149,14 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "ContractCallTxEvent", "payload" => %{"micro_index" => ^mbi} } = tx1 assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "ContractCallTxEvent", "payload" => %{"micro_index" => ^mbi} } = tx2 @@ -161,6 +176,9 @@ defmodule AeMdwWeb.ActivitiesControllerTest do height = 398 mbi = 2 create_txi = 432 + kb_hash = TS.key_block_hash(0) + mb_hash = TS.micro_block_hash(0) + enc_mb_hash = Enc.encode(:micro_block_hash, mb_hash) {:ok, aetx} = :aec_spend_tx.new(%{ @@ -202,6 +220,8 @@ defmodule AeMdwWeb.ActivitiesControllerTest do ) |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {2, 1})) |> Store.put(Model.Tx, Model.tx(index: 2, block_index: {height, mbi}, id: "hash2")) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash)) + |> Store.put(Model.Block, Model.block(index: {height, mbi}, hash: mb_hash)) with_mocks [ {Db, [], @@ -226,11 +246,13 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "InternalContractCallEvent" } = tx1 assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "InternalContractCallEvent" } = tx2 @@ -248,6 +270,9 @@ defmodule AeMdwWeb.ActivitiesControllerTest do account_id = :aeser_id.create(:account, account_pk) height = 398 mbi = 2 + kb_hash = TS.key_block_hash(0) + mb_hash = TS.micro_block_hash(0) + enc_mb_hash = Enc.encode(:micro_block_hash, mb_hash) {:ok, aetx} = :aec_spend_tx.new(%{ @@ -285,6 +310,8 @@ defmodule AeMdwWeb.ActivitiesControllerTest do ) |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {2, 1})) |> Store.put(Model.Tx, Model.tx(index: 2, block_index: {height, mbi}, id: "hash2")) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash)) + |> Store.put(Model.Block, Model.block(index: {height, mbi}, hash: mb_hash)) with_mocks [ {Db, [], @@ -309,11 +336,13 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "InternalContractCallEvent" } = tx1 assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash, "type" => "InternalContractCallEvent" } = tx2 @@ -329,6 +358,11 @@ defmodule AeMdwWeb.ActivitiesControllerTest do account = Enc.encode(:account_pubkey, account_pk) height = 398 [txi1, txi2, txi3] = [123, 456, 789] + kb_hash = TS.key_block_hash(0) + mb_hash1 = TS.micro_block_hash(0) + enc_mb_hash1 = Enc.encode(:micro_block_hash, mb_hash1) + mb_hash2 = TS.micro_block_hash(1) + enc_mb_hash2 = Enc.encode(:micro_block_hash, mb_hash2) store = empty_store() @@ -374,6 +408,9 @@ defmodule AeMdwWeb.ActivitiesControllerTest do ) ) |> Store.put(Model.Tx, Model.tx(index: txi3, block_index: {height, 1}, id: "hash3")) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash)) + |> Store.put(Model.Block, Model.block(index: {height, 0}, hash: mb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height, 1}, hash: mb_hash2)) assert %{"prev" => nil, "data" => [activity1, activity2] = data, "next" => next_url} = conn @@ -383,6 +420,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, + "block_hash" => ^enc_mb_hash1, "type" => "InternalTransferEvent", "payload" => %{ "kind" => "reward_oracle", @@ -393,6 +431,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, "type" => "InternalTransferEvent", + "block_hash" => ^enc_mb_hash2, "payload" => %{ "kind" => "fee_lock_name", "amount" => 20 @@ -416,6 +455,16 @@ defmodule AeMdwWeb.ActivitiesControllerTest do account = Enc.encode(:account_pubkey, account_pk) height = 398 [txi1, txi2, txi3] = [123, 456, 789] + kb_hash1 = TS.key_block_hash(0) + kb_hash2 = TS.key_block_hash(1) + kb_hash3 = TS.key_block_hash(2) + enc_kb_hash2 = Enc.encode(:key_block_hash, kb_hash2) + mb_hash1 = TS.micro_block_hash(0) + enc_mb_hash1 = Enc.encode(:micro_block_hash, mb_hash1) + mb_hash2 = TS.micro_block_hash(1) + enc_mb_hash2 = Enc.encode(:micro_block_hash, mb_hash2) + mb_hash3 = TS.micro_block_hash(2) + enc_mb_hash3 = Enc.encode(:micro_block_hash, mb_hash3) store = empty_store() @@ -474,6 +523,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do ) ) |> Store.put(Model.Tx, Model.tx(index: txi3, block_index: {height + 2, 0}, id: "hash3")) + |> Store.put(Model.Block, Model.block(index: {height, -1}, hash: kb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height + 1, -1}, hash: kb_hash2)) + |> Store.put(Model.Block, Model.block(index: {height + 2, -1}, hash: kb_hash3)) + |> Store.put(Model.Block, Model.block(index: {height, 0}, hash: mb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height, 1}, hash: mb_hash2)) + |> Store.put(Model.Block, Model.block(index: {height + 2, 0}, hash: mb_hash3)) assert %{ "prev" => nil, @@ -488,6 +543,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, "type" => "InternalTransferEvent", + "block_hash" => ^enc_mb_hash1, "payload" => %{ "kind" => "reward_oracle", "amount" => 10 @@ -497,6 +553,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, "type" => "InternalTransferEvent", + "block_hash" => ^enc_mb_hash2, "payload" => %{ "kind" => "fee_lock_name", "amount" => 20 @@ -506,6 +563,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => 399, "type" => "InternalTransferEvent", + "block_hash" => ^enc_kb_hash2, "payload" => %{ "kind" => "reward_dev", "amount" => 30 @@ -521,6 +579,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => 400, "type" => "InternalTransferEvent", + "block_hash" => ^enc_mb_hash3, "payload" => %{"kind" => "fee_lock_name", "amount" => 40} } = activity4 @@ -542,6 +601,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do tx3_hash = TS.tx_hash(2) tx1_encoded = Enc.encode(:tx_hash, tx1_hash) tx2_encoded = Enc.encode(:tx_hash, tx2_hash) + kb_hash1 = TS.key_block_hash(0) + kb_hash2 = TS.key_block_hash(1) + mb_hash1 = TS.key_block_hash(0) + enc_mb_hash1 = Enc.encode(:micro_block_hash, mb_hash1) + mb_hash2 = TS.key_block_hash(1) + enc_mb_hash2 = Enc.encode(:micro_block_hash, mb_hash2) store = empty_store() @@ -568,6 +633,10 @@ defmodule AeMdwWeb.ActivitiesControllerTest do Model.aexn_transfer(index: {:aex9, another_account_pk, txi3, account_pk, 3, 3}) ) |> Store.put(Model.Tx, Model.tx(index: txi3, block_index: {height2, 0}, id: tx3_hash)) + |> Store.put(Model.Block, Model.block(index: {height1, -1}, hash: kb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height1, 0}, hash: mb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height2, -1}, hash: kb_hash2)) + |> Store.put(Model.Block, Model.block(index: {height2, 0}, hash: mb_hash2)) assert %{"prev" => nil, "data" => [activity1, activity2], "next" => next_url} = conn @@ -578,6 +647,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height1, "type" => "Aex9TransferEvent", + "block_hash" => ^enc_mb_hash1, "payload" => %{ "amount" => 1, "log_idx" => 1, @@ -590,6 +660,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height2, "type" => "Aex141TransferEvent", + "block_hash" => ^enc_mb_hash2, "payload" => %{ "sender_id" => ^another_account, "recipient_id" => ^account, @@ -616,6 +687,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do txi1 = 123 txi2 = 456 txi3 = 789 + kb_hash1 = TS.key_block_hash(0) + kb_hash2 = TS.key_block_hash(1) + mb_hash1 = TS.micro_block_hash(0) + enc_mb_hash1 = Enc.encode(:micro_block_hash, mb_hash1) + mb_hash2 = TS.micro_block_hash(1) + enc_mb_hash2 = Enc.encode(:micro_block_hash, mb_hash2) store = empty_store() @@ -642,6 +719,10 @@ defmodule AeMdwWeb.ActivitiesControllerTest do Model.aexn_transfer(index: {:aex9, another_account_pk, txi3, account_pk, 3, 3}) ) |> Store.put(Model.Tx, Model.tx(index: txi3, block_index: {height2, 0}, id: "hash3")) + |> Store.put(Model.Block, Model.block(index: {height1, -1}, hash: kb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height1, 0}, hash: mb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height2, -1}, hash: kb_hash2)) + |> Store.put(Model.Block, Model.block(index: {height2, 0}, hash: mb_hash2)) assert %{"prev" => nil, "data" => [activity1, activity2], "next" => next_url} = conn @@ -651,6 +732,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height2, + "block_hash" => ^enc_mb_hash2, "type" => "Aex9TransferEvent", "payload" => %{ "sender_id" => ^another_account, @@ -662,6 +744,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height2, + "block_hash" => ^enc_mb_hash2, "type" => "Aex141TransferEvent", "payload" => %{ "sender_id" => ^another_account, @@ -679,6 +762,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height1, + "block_hash" => ^enc_mb_hash1, "type" => "Aex9TransferEvent", "payload" => %{ "sender_id" => ^account, @@ -709,6 +793,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do encoded_tx_hash1 = Enc.encode(:tx_hash, tx_hash1) encoded_tx_hash2 = Enc.encode(:tx_hash, tx_hash2) encoded_tx_hash3 = Enc.encode(:tx_hash, tx_hash3) + kb_hash1 = TS.key_block_hash(0) + kb_hash2 = TS.key_block_hash(1) + mb_hash1 = TS.micro_block_hash(0) + mb_hash2 = TS.micro_block_hash(1) + enc_mb_hash1 = Enc.encode(:micro_block_hash, mb_hash1) + enc_mb_hash2 = Enc.encode(:micro_block_hash, mb_hash2) {:ok, aetx1} = :aens_claim_tx.new(%{ @@ -774,8 +864,10 @@ defmodule AeMdwWeb.ActivitiesControllerTest do Model.Tx, Model.tx(index: txi3, block_index: {height2, 0}, id: tx_hash3, time: 30) ) - |> Store.put(Model.Block, Model.block(index: {height1, 0}, hash: "bhash1")) - |> Store.put(Model.Block, Model.block(index: {height2, 0}, hash: "bhash2")) + |> Store.put(Model.Block, Model.block(index: {height1, 0}, hash: mb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height2, 0}, hash: mb_hash2)) + |> Store.put(Model.Block, Model.block(index: {height1, -1}, hash: kb_hash1)) + |> Store.put(Model.Block, Model.block(index: {height2, -1}, hash: kb_hash2)) with_mocks [ {Db, [], @@ -801,6 +893,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height2, "type" => "NameClaimEvent", + "block_hash" => ^enc_mb_hash2, "payload" => %{ "tx_hash" => ^encoded_tx_hash3, "micro_time" => 30, @@ -820,6 +913,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height2, "type" => "NameClaimEvent", + "block_hash" => ^enc_mb_hash2, "payload" => %{ "tx_hash" => ^encoded_tx_hash2, "micro_time" => 20, @@ -845,6 +939,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height1, "type" => "NameClaimEvent", + "block_hash" => ^enc_mb_hash1, "payload" => %{ "tx_hash" => ^encoded_tx_hash1, "micro_time" => 10,