From dd33cf335826d453a5926b1dcb0b260f7f97921a Mon Sep 17 00:00:00 2001 From: Sebastian Borrazas Date: Thu, 22 Sep 2022 07:40:02 -0300 Subject: [PATCH 1/4] feat: include internal transactions as activities --- README.md | 37 ++++ lib/ae_mdw/activities.ex | 180 +++++++++++++--- lib/ae_mdw/fields.ex | 24 +-- lib/ae_mdw/txs.ex | 24 +-- .../activities_controller_test.exs | 194 ++++++++++++++++++ 5 files changed, 395 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 0d51b1bd5..1ab962dbc 100644 --- a/README.md +++ b/README.md @@ -4412,6 +4412,8 @@ Each activity contains 3 values: For transaction events the activity type will be `Event`, and the payload will contain a single transaction object as displayed in the `/v2/txs` endpoint. +Transaction events can also be `IntContractCallEvents` which represent transactions that happen internally during a contract call. + ``` $ curl https://mainnet.aeternity.io/mdw/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm1N2WKoAGyL7abTAHF1wGMPjzx/activities { @@ -4471,6 +4473,41 @@ $ curl https://mainnet.aeternity.io/mdw/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm }, "type": "SpendTxEvent", "height": 502033 + }, + { + "height": 659373, + "payload": { + "block_hash": "mh_MXVb7wmE1tqeA2xSPhTTksLy7DE5PvR8nsu5haC2fTGpgxxhR", + "call_tx_hash": "th_Ugtejdn7SkJHXkC3VSdCm2SnXGgPxHgUphBneMqgR3gniZzDN", + "call_txi": 34224137, + "contract_id": "ct_2AfnEfCSZCTEkxL5Yoi4Yfq6fF7YapHRaFKDJK3THMXMBspp5z", + "contract_tx_hash": "th_6memqAr5S3UQp1pc4FWXT8xUotfdrdUFgBd8VPmjM2ZRuojTF", + "contract_txi": 8392766, + "function": "Oracle.query", + "height": 659373, + "internal_tx": { + "fee": 0, + "nonce": 0, + "oracle_id": "ok_AFbLSrppnBFgbKPo4GykK5XEwdq15oXgosgcdL7ud6Vo2YPsH", + "query": "YWtfcjNxRWNzWWd5Z2JjYVoxZlhQRFB0YThnZU5FUkV0OHZZaVVKNWtxQnNRNDhXVmp4NztodHRwczovL20ud2VpYm8uY24vNzc1NDY0Njg4Ny80ODE2MjEwNDI2ODYxMjg5", + "query_fee": 20000000000000, + "query_id": "oq_pcJy4ufijeP56LwCaJ47GcRNvJvW5nEUedR4BNeMzSobXXqMx", + "query_ttl": { + "type": "delta", + "value": 20 + }, + "response_ttl": { + "type": "delta", + "value": 20 + }, + "sender_id": "ak_7wqP18AHzyoqymwGaqQp8G2UpzBCggYiq7CZdJiB71VUsLpR4", + "type": "OracleQueryTx", + "version": 1 + }, + "local_idx": 3, + "micro_index": 0 + }, + "type": "IntContractCallEvent" } ], "next": "/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm1N2WKoAGyL7abTAHF1wGMPjzx/activities?cursor=84328-2002003-0", diff --git a/lib/ae_mdw/activities.ex b/lib/ae_mdw/activities.ex index 8280f7a75..919539f45 100644 --- a/lib/ae_mdw/activities.ex +++ b/lib/ae_mdw/activities.ex @@ -4,13 +4,17 @@ defmodule AeMdw.Activities do """ alias AeMdw.Blocks alias AeMdw.Collection + alias AeMdw.Db.Format alias AeMdw.Db.Model + alias AeMdw.Db.Origin alias AeMdw.Db.State + alias AeMdw.Db.Util, as: DbUtil alias AeMdw.Error alias AeMdw.Error.Input, as: ErrInput alias AeMdw.Fields alias AeMdw.Node alias AeMdw.Txs + alias AeMdw.Util alias AeMdw.Validate require Model @@ -24,9 +28,16 @@ defmodule AeMdw.Activities do @typep cursor() :: binary() | nil @typep txi() :: Txs.txi() @typep activity_key() :: {Blocks.height(), txi(), non_neg_integer()} - @typep activity_value() :: {:field, Node.tx_type(), non_neg_integer() | nil} + @typep activity_value() :: + {:field, Node.tx_type(), non_neg_integer() | nil} + | :int_contract_call + | {:int_contract_external_call, non_neg_integer()} @typep activity_pair() :: {activity_key(), activity_value()} + @max_pos 4 + @min_int Util.min_int() + @max_int -@min_int + @doc """ Activities related to an account are those that affect the account in any way. @@ -63,10 +74,58 @@ defmodule AeMdw.Activities do {:ok, cursor} <- deserialize_cursor(cursor) do {prev_cursor, activities_locators_data, next_cursor} = fn direction -> - gens_stream = build_gens_stream(state, direction, account_pk, range, cursor) - txs_stream = build_txs_stream(state, direction, account_pk, range, cursor) + {txi_scope, gen_scope} = + case range do + {:gen, %Range{first: first_gen, last: last_gen}} -> + { + {first_gen, last_gen}, + {DbUtil.first_gen_to_txi(state, first_gen, direction), + DbUtil.last_gen_to_txi(state, last_gen, direction)} + } + + nil -> + {nil, nil} + end + + {txi_cursor, local_idx_cursor} = + case cursor do + {_height, txi, local_idx} -> {txi, local_idx} + nil -> {nil, nil} + end + + gens_stream = build_gens_stream(state, direction, account_pk, gen_scope, cursor) + txs_stream = build_txs_stream(state, direction, account_pk, txi_scope, txi_cursor) + + int_contract_calls_stream = + build_int_contract_calls_stream(state, direction, account_pk, txi_scope, cursor) + + ext_contract_calls_stream = + build_ext_contract_calls_stream(state, direction, account_pk, txi_scope, cursor) + + stream = + [ + txs_stream, + gens_stream, + ext_contract_calls_stream, + int_contract_calls_stream + ] + |> Collection.merge(direction) + |> Stream.dedup_by(&elem(&1, 0)) + + if local_idx_cursor do + Stream.drop_while(stream, fn + {{_height, ^txi_cursor, local_idx}, _data} when direction == :forward -> + local_idx < local_idx_cursor + + {{_height, ^txi_cursor, local_idx}, _data} when direction == :backward -> + local_idx > local_idx_cursor - Collection.merge([txs_stream, gens_stream], direction) + _activity_pair -> + false + end) + else + stream + end end |> Collection.paginate(pagination) @@ -75,47 +134,88 @@ defmodule AeMdw.Activities do end end - defp build_gens_stream(_state, _direction, _account_pk, _range, _cursor) do + defp build_gens_stream(_state, _direction, _account_pk, _gen_scope, _cursor) do [] end - defp build_txs_stream(state, direction, account_pk, range, cursor) do - {txi_cursor, local_idx_cursor} = - case cursor do - {_height, txi, local_idx} -> {txi, local_idx} - nil -> {nil, nil} - end + defp build_ext_contract_calls_stream(state, direction, account_pk, txi_scope, cursor) do + 0..@max_pos + |> Enum.map(fn pos -> + key_boundary = + case txi_scope do + {first_txi, last_txi} -> + {{account_pk, pos, first_txi, @min_int}, {account_pk, pos, last_txi, @max_int}} - stream = - state - |> Fields.account_fields_stream(account_pk, direction, range, txi_cursor) - |> Stream.transform({-1, -1, -1}, fn - {txi, tx_type, tx_field_pos}, {txi, height, local_idx} -> - {[{{height, txi, local_idx + 1}, {:field, tx_type, tx_field_pos}}], - {txi, height, local_idx + 1}} + nil -> + {{account_pk, pos, @min_int, nil}, {account_pk, pos, @max_int, nil}} + end - {txi, tx_type, tx_field_pos}, _acc -> - Model.tx(block_index: {height, _mbi}) = State.fetch!(state, Model.Tx, txi) + cursor = + case cursor do + {_height, txi_cursor, local_idx_cursor} -> + {account_pk, pos, txi_cursor, local_idx_cursor} + + nil -> + nil + end - {[{{height, txi, 0}, {:field, tx_type, tx_field_pos}}], {txi, height, 0}} + state + |> Collection.stream(Model.IdIntContractCall, direction, key_boundary, cursor) + |> Stream.map(fn {^account_pk, ^pos, txi, local_idx} -> + Model.tx(block_index: {height, _mbi}) = State.fetch!(state, Model.Tx, txi) + + {{height, txi, local_idx}, {:int_contract_external_call, pos}} end) + end) + |> Collection.merge(direction) + end - if local_idx_cursor do - Stream.drop_while(stream, fn - {{_height, ^txi_cursor, local_idx}, _data} when direction == :forward -> - local_idx < local_idx_cursor + defp build_int_contract_calls_stream(state, direction, account_pk, txi_scope, cursor) do + case Origin.tx_index(state, {:contract, account_pk}) do + {:ok, create_txi} -> + key_boundary = + case txi_scope do + {first_txi, last_txi} -> + {{create_txi, first_txi, @min_int}, {create_txi, last_txi, @max_int}} - {{_height, ^txi_cursor, local_idx}, _data} when direction == :backward -> - local_idx > local_idx_cursor + nil -> + {{create_txi, @min_int, @min_int}, {create_txi, @max_int, @max_int}} + end - _activity_pair -> - false - end) - else - stream + cursor = + case cursor do + {_height, txi_cursor, local_idx_cursor} -> {create_txi, txi_cursor, local_idx_cursor} + nil -> nil + end + + state + |> Collection.stream(Model.GrpIntContractCall, direction, key_boundary, cursor) + |> Stream.map(fn {^create_txi, txi, local_idx} -> + Model.tx(block_index: {height, _mbi}) = State.fetch!(state, Model.Tx, txi) + + {{height, txi, local_idx}, :int_contract_call} + end) + + :not_found -> + [] end end + defp build_txs_stream(state, direction, account_pk, range, txi_cursor) do + state + |> Fields.account_fields_stream(account_pk, direction, range, txi_cursor) + |> Stream.transform({-1, -1, -1}, fn + {txi, tx_type, tx_field_pos}, {txi, height, local_idx} -> + {[{{height, txi, local_idx + 1}, {:field, tx_type, tx_field_pos}}], + {txi, height, local_idx + 1}} + + {txi, tx_type, tx_field_pos}, _acc -> + Model.tx(block_index: {height, _mbi}) = State.fetch!(state, Model.Tx, txi) + + {[{{height, txi, 0}, {:field, tx_type, tx_field_pos}}], {txi, height, 0}} + end) + end + @spec render(state(), activity_pair()) :: map() defp render(state, {{height, txi, _local_idx}, {:field, tx_type, _tx_pos}}) do tx = state |> Txs.fetch!(txi) |> Map.delete("tx_index") @@ -127,6 +227,22 @@ defmodule AeMdw.Activities do } end + defp render(state, {{height, call_txi, local_idx}, :int_contract_call}) do + %{ + height: height, + type: "IntContractCallEvent", + payload: Format.to_map(state, {call_txi, local_idx}, Model.IntContractCall) + } + end + + defp render(state, {{height, call_txi, local_idx}, {:int_contract_external_call, _pos}}) do + %{ + height: height, + type: "IntContractCallEvent", + payload: Format.to_map(state, {call_txi, local_idx}, Model.IntContractCall) + } + end + defp serialize_cursor(nil), do: nil defp serialize_cursor({{{height, txi, local_idx}, _data}, is_reversed?}), diff --git a/lib/ae_mdw/fields.ex b/lib/ae_mdw/fields.ex index a53f9cf3a..6f55438d2 100644 --- a/lib/ae_mdw/fields.ex +++ b/lib/ae_mdw/fields.ex @@ -6,7 +6,6 @@ defmodule AeMdw.Fields do alias AeMdw.Collection alias AeMdw.Db.Model alias AeMdw.Db.State - alias AeMdw.Db.Util, as: DbUtil alias AeMdw.Node alias AeMdw.Node.Db alias AeMdw.Txs @@ -15,23 +14,14 @@ defmodule AeMdw.Fields do @typep state() :: State.t() @typep pubkey() :: Db.pubkey() @typep direction() :: Collection.direction() - @typep range() :: {:gen, Range.t()} | nil - @typep cursor() :: Txs.tx() | nil + @typep txi_scope() :: {Txs.txi(), Txs.txi()} | nil + @typep cursor() :: Txs.txi() | nil @create_tx_types ~w(contract_create_tx channel_create_tx oracle_register_tx ga_attach_tx)a - @spec account_fields_stream(state(), pubkey(), direction(), range(), cursor()) :: Enumerable.t() - def account_fields_stream(state, account_pk, direction, range, cursor) do - scope = - case range do - {:gen, %Range{first: first_gen, last: last_gen}} -> - {DbUtil.first_gen_to_txi(state, first_gen, direction), - DbUtil.last_gen_to_txi(state, last_gen, direction)} - - nil -> - nil - end - + @spec account_fields_stream(state(), pubkey(), direction(), txi_scope(), cursor()) :: + Enumerable.t() + def account_fields_stream(state, account_pk, direction, txi_scope, cursor) do Node.tx_types() |> Enum.flat_map(fn tx_type -> types_pos = @@ -47,14 +37,14 @@ defmodule AeMdw.Fields do end) |> Enum.map(fn {tx_type, tx_field_pos} -> scope = - case scope do + case txi_scope do {first_txi, last_txi} -> {{tx_type, tx_field_pos, account_pk, first_txi}, {tx_type, tx_field_pos, account_pk, last_txi}} nil -> {{tx_type, tx_field_pos, account_pk, Util.min_int()}, - {tx_type, tx_field_pos, account_pk, Util.max_256bit_int()}} + {tx_type, tx_field_pos, account_pk, -Util.min_int()}} end cursor = if cursor, do: {tx_type, tx_field_pos, account_pk, cursor} diff --git a/lib/ae_mdw/txs.ex b/lib/ae_mdw/txs.ex index 7ae44972a..b848458ba 100644 --- a/lib/ae_mdw/txs.ex +++ b/lib/ae_mdw/txs.ex @@ -295,21 +295,15 @@ defmodule AeMdw.Txs do initial_tx_types = initial_fields |> Enum.map(fn {tx_type, _pos} -> tx_type end) |> MapSet.new() - intersection_of_tx_types = - Enum.reduce(ids_fields_rest, initial_tx_types, fn {_id, fields}, acc -> - fields - |> Enum.map(fn {tx_type, _pos} -> tx_type end) - |> MapSet.new() - |> MapSet.intersection(acc) - end) - - intersection_of_tx_types = - case types do - [] -> intersection_of_tx_types - _types -> MapSet.intersection(intersection_of_tx_types, MapSet.new(types)) - end - - Enum.flat_map(intersection_of_tx_types, fn tx_type -> + ids_fields_rest + |> Enum.map(fn {_id, fields} -> + fields + |> Enum.map(fn {tx_type, _pos} -> tx_type end) + |> MapSet.new() + end) + |> Enum.reduce(initial_tx_types, &MapSet.intersection/2) + |> MapSet.intersection(MapSet.new(types)) + |> Enum.flat_map(fn tx_type -> {min_account_id, min_fields} = Enum.min_by(ids_fields, fn {id, fields} -> count_txs_for_account(state, id, fields, tx_type) diff --git a/test/ae_mdw_web/controllers/activities_controller_test.exs b/test/ae_mdw_web/controllers/activities_controller_test.exs index c2ed7c912..3938fc280 100644 --- a/test/ae_mdw_web/controllers/activities_controller_test.exs +++ b/test/ae_mdw_web/controllers/activities_controller_test.exs @@ -3,6 +3,7 @@ defmodule AeMdwWeb.ActivitiesControllerTest do @moduletag skip_store: true alias :aeser_api_encoder, as: Enc + alias AeMdw.Db.Format alias AeMdw.Db.MemStore alias AeMdw.Db.Model alias AeMdw.Db.NullStore @@ -151,6 +152,199 @@ defmodule AeMdwWeb.ActivitiesControllerTest do URI.decode_query(query) end end + + test "when it has int contract calls internally", %{conn: conn} do + contract_pk = TS.address(0) + contract = Enc.encode(:contract_pubkey, contract_pk) + account_pk = TS.address(1) + account_id = :aeser_id.create(:account, account_pk) + height = 398 + mbi = 2 + create_txi = 432 + + {:ok, aetx} = + :aec_spend_tx.new(%{ + sender_id: account_id, + recipient_id: account_id, + amount: 2, + fee: 3, + nonce: 4, + payload: "" + }) + + {:spend_tx, tx} = :aetx.specialize_type(aetx) + + store = + empty_store() + |> Store.put( + Model.Field, + Model.field(index: {:contract_create_tx, nil, contract_pk, create_txi}) + ) + |> Store.put( + Model.GrpIntContractCall, + Model.grp_int_contract_call(index: {create_txi, 1, 0}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {1, 0})) + |> Store.put( + Model.GrpIntContractCall, + Model.grp_int_contract_call(index: {create_txi, 1, 1}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {1, 1})) + |> Store.put(Model.Tx, Model.tx(index: 1, block_index: {height, mbi}, id: "hash1")) + |> Store.put( + Model.GrpIntContractCall, + Model.grp_int_contract_call(index: {create_txi, 2, 0}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {2, 0})) + |> Store.put( + Model.GrpIntContractCall, + Model.grp_int_contract_call(index: {create_txi, 2, 1}) + ) + |> 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")) + + with_mocks [ + {Db, [], + [ + get_tx_data: fn + "hash1" -> + {"", :spend_tx, aetx, tx} + + "hash2" -> + {"", :spend_tx, aetx, tx} + end + ]}, + {:aec_db, [], [get_header: fn _block_hash -> :header end]}, + {:aetx_sign, [], [serialize_for_client: fn :header, ^aetx -> %{} end]}, + {Format, [], [to_map: fn _state, _record, _tab -> %{} end]} + ] do + assert %{"prev" => nil, "data" => [tx1, tx2], "next" => next_url} = + conn + |> with_store(store) + |> get("/v2/accounts/#{contract}/activities", direction: "forward", limit: 2) + |> json_response(200) + + assert %{ + "height" => ^height, + "type" => "IntContractCallEvent" + } = tx1 + + assert %{ + "height" => ^height, + "type" => "IntContractCallEvent" + } = tx2 + + assert %URI{query: query} = URI.parse(next_url) + + assert %{"cursor" => _cursor, "direction" => "forward", "limit" => "2"} = + URI.decode_query(query) + end + end + + test "when it has int contract calls externally", %{conn: conn} do + contract_pk = TS.address(0) + contract = Enc.encode(:contract_pubkey, contract_pk) + account_pk = TS.address(1) + account_id = :aeser_id.create(:account, account_pk) + height = 398 + mbi = 2 + + {:ok, aetx} = + :aec_spend_tx.new(%{ + sender_id: account_id, + recipient_id: account_id, + amount: 2, + fee: 3, + nonce: 4, + payload: "" + }) + + {:spend_tx, tx} = :aetx.specialize_type(aetx) + + store = + empty_store() + |> Store.put( + Model.IdIntContractCall, + Model.id_int_contract_call(index: {contract_pk, 1, 1, 0}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {1, 0})) + |> Store.put( + Model.IdIntContractCall, + Model.id_int_contract_call(index: {contract_pk, 1, 1, 1}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {1, 1})) + |> Store.put(Model.Tx, Model.tx(index: 1, block_index: {height, mbi}, id: "hash1")) + |> Store.put( + Model.IdIntContractCall, + Model.id_int_contract_call(index: {contract_pk, 3, 2, 0}) + ) + |> Store.put(Model.IntContractCall, Model.int_contract_call(index: {2, 0})) + |> Store.put( + Model.IdIntContractCall, + Model.id_int_contract_call(index: {contract_pk, 1, 2, 1}) + ) + |> 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")) + + with_mocks [ + {Db, [], + [ + get_tx_data: fn + "hash1" -> + {"", :spend_tx, aetx, tx} + + "hash2" -> + {"", :spend_tx, aetx, tx} + end + ]}, + {:aec_db, [], [get_header: fn _block_hash -> :header end]}, + {:aetx_sign, [], [serialize_for_client: fn :header, ^aetx -> %{} end]}, + {Format, [], [to_map: fn _state, _record, _tab -> %{} end]} + ] do + assert %{"prev" => nil, "data" => [tx1, tx2], "next" => next_url} = + conn + |> with_store(store) + |> get("/v2/accounts/#{contract}/activities", direction: "forward", limit: 2) + |> json_response(200) + + assert %{ + "height" => ^height, + "type" => "IntContractCallEvent" + } = tx1 + + assert %{ + "height" => ^height, + "type" => "IntContractCallEvent" + } = tx2 + + assert %URI{query: query} = URI.parse(next_url) + + assert %{"cursor" => _cursor, "direction" => "forward", "limit" => "2"} = + URI.decode_query(query) + end + end + + test "when the account is invalid", %{conn: conn} do + invalid_account = "ak_foo" + error_msg = "invalid id: #{invalid_account}" + + assert %{"error" => ^error_msg} = + conn + |> get("/v2/accounts/#{invalid_account}/activities") + |> json_response(400) + end + + test "when cursor is invalid", %{conn: conn} do + account_pk = TS.address(0) + account = Enc.encode(:account_pubkey, account_pk) + invalid_cursor = "1290318-aa-bb" + error_msg = "invalid cursor: #{invalid_cursor}" + + assert %{"error" => ^error_msg} = + conn + |> get("/v2/accounts/#{account}/activities", cursor: invalid_cursor) + |> json_response(400) + end end defp empty_store, do: NullStore.new() |> MemStore.new() From 76f4ef8f9528fa55f07bce49789b121c0149c14c Mon Sep 17 00:00:00 2001 From: Sebastian Borrazas Date: Thu, 22 Sep 2022 13:49:51 -0300 Subject: [PATCH 2/4] refactor: use new funs/syntax for the new code --- lib/ae_mdw/activities.ex | 15 +++------------ lib/ae_mdw/fields.ex | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/ae_mdw/activities.ex b/lib/ae_mdw/activities.ex index 919539f45..b94982696 100644 --- a/lib/ae_mdw/activities.ex +++ b/lib/ae_mdw/activities.ex @@ -31,12 +31,11 @@ defmodule AeMdw.Activities do @typep activity_value() :: {:field, Node.tx_type(), non_neg_integer() | nil} | :int_contract_call - | {:int_contract_external_call, non_neg_integer()} @typep activity_pair() :: {activity_key(), activity_value()} @max_pos 4 @min_int Util.min_int() - @max_int -@min_int + @max_int Util.max_int() @doc """ Activities related to an account are those that affect the account in any way. @@ -76,7 +75,7 @@ defmodule AeMdw.Activities do fn direction -> {txi_scope, gen_scope} = case range do - {:gen, %Range{first: first_gen, last: last_gen}} -> + {:gen, first_gen..last_gen} -> { {first_gen, last_gen}, {DbUtil.first_gen_to_txi(state, first_gen, direction), @@ -164,7 +163,7 @@ defmodule AeMdw.Activities do |> Stream.map(fn {^account_pk, ^pos, txi, local_idx} -> Model.tx(block_index: {height, _mbi}) = State.fetch!(state, Model.Tx, txi) - {{height, txi, local_idx}, {:int_contract_external_call, pos}} + {{height, txi, local_idx}, :int_contract_call} end) end) |> Collection.merge(direction) @@ -235,14 +234,6 @@ defmodule AeMdw.Activities do } end - defp render(state, {{height, call_txi, local_idx}, {:int_contract_external_call, _pos}}) do - %{ - height: height, - type: "IntContractCallEvent", - payload: Format.to_map(state, {call_txi, local_idx}, Model.IntContractCall) - } - end - defp serialize_cursor(nil), do: nil defp serialize_cursor({{{height, txi, local_idx}, _data}, is_reversed?}), diff --git a/lib/ae_mdw/fields.ex b/lib/ae_mdw/fields.ex index 6f55438d2..b270d4176 100644 --- a/lib/ae_mdw/fields.ex +++ b/lib/ae_mdw/fields.ex @@ -44,7 +44,7 @@ defmodule AeMdw.Fields do nil -> {{tx_type, tx_field_pos, account_pk, Util.min_int()}, - {tx_type, tx_field_pos, account_pk, -Util.min_int()}} + {tx_type, tx_field_pos, account_pk, Util.max_int()}} end cursor = if cursor, do: {tx_type, tx_field_pos, account_pk, cursor} From b784b8a3c90ea8445215ef6c4c42752057fbd069 Mon Sep 17 00:00:00 2001 From: Sebastian Borrazas Date: Fri, 23 Sep 2022 07:48:15 -0300 Subject: [PATCH 3/4] refactor: rename internal contract call activity events --- lib/ae_mdw/activities.ex | 2 +- .../ae_mdw_web/controllers/activities_controller_test.exs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ae_mdw/activities.ex b/lib/ae_mdw/activities.ex index b94982696..7e85034a0 100644 --- a/lib/ae_mdw/activities.ex +++ b/lib/ae_mdw/activities.ex @@ -229,7 +229,7 @@ defmodule AeMdw.Activities do defp render(state, {{height, call_txi, local_idx}, :int_contract_call}) do %{ height: height, - type: "IntContractCallEvent", + type: "InternalContractCallEvent", payload: Format.to_map(state, {call_txi, local_idx}, Model.IntContractCall) } end diff --git a/test/ae_mdw_web/controllers/activities_controller_test.exs b/test/ae_mdw_web/controllers/activities_controller_test.exs index 3938fc280..dc03b97d3 100644 --- a/test/ae_mdw_web/controllers/activities_controller_test.exs +++ b/test/ae_mdw_web/controllers/activities_controller_test.exs @@ -226,12 +226,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, - "type" => "IntContractCallEvent" + "type" => "InternalContractCallEvent" } = tx1 assert %{ "height" => ^height, - "type" => "IntContractCallEvent" + "type" => "InternalContractCallEvent" } = tx2 assert %URI{query: query} = URI.parse(next_url) @@ -309,12 +309,12 @@ defmodule AeMdwWeb.ActivitiesControllerTest do assert %{ "height" => ^height, - "type" => "IntContractCallEvent" + "type" => "InternalContractCallEvent" } = tx1 assert %{ "height" => ^height, - "type" => "IntContractCallEvent" + "type" => "InternalContractCallEvent" } = tx2 assert %URI{query: query} = URI.parse(next_url) From 1b733db36989ffbbb76477a1fdbe94b9af1d0395 Mon Sep 17 00:00:00 2001 From: Sebastian Borrazas Date: Sun, 25 Sep 2022 15:38:51 -0300 Subject: [PATCH 4/4] docs: update InternalContractCallEvent type on README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ab962dbc..7d5795400 100644 --- a/README.md +++ b/README.md @@ -4412,7 +4412,7 @@ Each activity contains 3 values: For transaction events the activity type will be `Event`, and the payload will contain a single transaction object as displayed in the `/v2/txs` endpoint. -Transaction events can also be `IntContractCallEvents` which represent transactions that happen internally during a contract call. +Transaction events can also be `InternalContractCallEvent` which represent transactions that happen internally during a contract call. ``` $ curl https://mainnet.aeternity.io/mdw/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm1N2WKoAGyL7abTAHF1wGMPjzx/activities @@ -4507,7 +4507,7 @@ $ curl https://mainnet.aeternity.io/mdw/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm "local_idx": 3, "micro_index": 0 }, - "type": "IntContractCallEvent" + "type": "InternalContractCallEvent" } ], "next": "/v2/accounts/ak_2nVdbZTBVTbAet8j2hQhLmfNm1N2WKoAGyL7abTAHF1wGMPjzx/activities?cursor=84328-2002003-0",