From 8abd27fbea7ef5459b750757cbef1e9948057b54 Mon Sep 17 00:00:00 2001 From: Samuel Manzanera Date: Thu, 15 Sep 2022 20:44:32 +0200 Subject: [PATCH] Define the limit on the P2P message instead of GraphQL --- lib/archethic.ex | 13 +++++++---- lib/archethic/p2p/message.ex | 23 ++++++++++++++----- .../p2p/message/get_transaction_inputs.ex | 5 ++-- lib/archethic/transaction_chain.ex | 18 ++++++++++----- lib/archethic_web/graphql_schema/resolver.ex | 2 +- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/lib/archethic.ex b/lib/archethic.ex index 98b9ececa..1827ae722 100644 --- a/lib/archethic.ex +++ b/lib/archethic.ex @@ -182,9 +182,14 @@ defmodule Archethic do @doc """ Request to fetch the inputs for a transaction address from the closest nodes at a given page """ - @spec get_transaction_inputs(binary(), non_neg_integer()) :: list(TransactionInput.t()) - def get_transaction_inputs(address, page) - when is_binary(address) and is_integer(page) and page >= 0 do + @spec get_transaction_inputs( + binary(), + paging_offset :: non_neg_integer(), + limit :: non_neg_integer() + ) :: list(TransactionInput.t()) + def get_transaction_inputs(address, page, limit) + when is_binary(address) and is_integer(page) and page >= 0 and is_integer(limit) and + limit >= 0 do nodes = address |> Election.chain_storage_nodes(P2P.authorized_and_available_nodes()) @@ -192,7 +197,7 @@ defmodule Archethic do |> Enum.filter(&Node.locally_available?/1) {inputs, _more?, _offset} = - TransactionChain.fetch_inputs_remotely(address, nodes, DateTime.utc_now(), page) + TransactionChain.fetch_inputs_remotely(address, nodes, DateTime.utc_now(), page, limit) inputs end diff --git a/lib/archethic/p2p/message.ex b/lib/archethic/p2p/message.ex index 9d9ce1c4e..e8cab3772 100644 --- a/lib/archethic/p2p/message.ex +++ b/lib/archethic/p2p/message.ex @@ -348,8 +348,9 @@ defmodule Archethic.P2P.Message do <<16::8, address::binary>> end - def encode(%GetTransactionInputs{address: address, offset: offset}) do - <<17::8, address::binary, VarInt.from_value(offset)::binary>> + def encode(%GetTransactionInputs{address: address, offset: offset, limit: limit}) do + <<17::8, address::binary, VarInt.from_value(offset)::binary, + VarInt.from_value(limit)::binary>> end def encode(%GetTransactionChainLength{address: address}) do @@ -829,7 +830,8 @@ defmodule Archethic.P2P.Message do def decode(<<17::8, rest::bitstring>>) do {address, rest} = Utils.deserialize_address(rest) {offset, rest} = VarInt.get_value(rest) - {%GetTransactionInputs{address: address, offset: offset}, rest} + {limit, rest} = VarInt.get_value(rest) + {%GetTransactionInputs{address: address, offset: offset, limit: limit}, rest} end def decode(<<18::8, rest::bitstring>>) do @@ -1500,7 +1502,7 @@ defmodule Archethic.P2P.Message do } end - def process(%GetTransactionInputs{address: address, offset: offset}) do + def process(%GetTransactionInputs{address: address, offset: offset, limit: limit}) do contract_inputs = address |> Contracts.list_contract_transactions() @@ -1525,7 +1527,16 @@ defmodule Archethic.P2P.Message do input_size = TransactionInput.serialize(input) |> byte_size - if acc_size + input_size < 3_000_000 do + size_capacity? = acc_size + input_size < 3_000_000 + + should_take_more? = + if limit > 0 do + length(acc.inputs) < limit and size_capacity? + else + size_capacity? + end + + if should_take_more? do new_acc = acc |> Map.update!(:inputs, &[input | &1]) @@ -1539,7 +1550,7 @@ defmodule Archethic.P2P.Message do end) %TransactionInputList{ - inputs: inputs, + inputs: Enum.reverse(inputs), more?: more?, offset: offset } diff --git a/lib/archethic/p2p/message/get_transaction_inputs.ex b/lib/archethic/p2p/message/get_transaction_inputs.ex index 78851a6c7..4ecf08e2f 100644 --- a/lib/archethic/p2p/message/get_transaction_inputs.ex +++ b/lib/archethic/p2p/message/get_transaction_inputs.ex @@ -3,12 +3,13 @@ defmodule Archethic.P2P.Message.GetTransactionInputs do Represents a message with to request the inputs (spent or unspents) from a transaction """ @enforce_keys [:address] - defstruct [:address, offset: 0] + defstruct [:address, offset: 0, limit: 0] alias Archethic.Crypto @type t :: %__MODULE__{ address: Crypto.versioned_hash(), - offset: non_neg_integer() + offset: non_neg_integer(), + limit: non_neg_integer() } end diff --git a/lib/archethic/transaction_chain.ex b/lib/archethic/transaction_chain.ex index 2c1ad5371..076b8becd 100644 --- a/lib/archethic/transaction_chain.ex +++ b/lib/archethic/transaction_chain.ex @@ -752,13 +752,19 @@ defmodule Archethic.TransactionChain do If the inputs exist, then they are returned in the shape of `{:ok, inputs}`. If no nodes are able to answer the request, `{:error, :network_issue}` is returned. """ - @spec fetch_inputs_remotely(address :: Crypto.versioned_hash(), list(Node.t()), DateTime.t()) :: + @spec fetch_inputs_remotely( + address :: Crypto.versioned_hash(), + list(Node.t()), + DateTime.t(), + limit :: non_neg_integer() + ) :: {inputs :: list(TransactionInput.t()), more? :: boolean(), offset :: non_neg_integer()} - def fetch_inputs_remotely(address, nodes, timestamp, offset \\ 0) - def fetch_inputs_remotely(_, [], _, _), do: {[], false, 0} + def fetch_inputs_remotely(address, nodes, timestamp, offset \\ 0, limit \\ 0) + def fetch_inputs_remotely(_, [], _, _, _), do: {[], false, 0} - def fetch_inputs_remotely(address, nodes, timestamp = %DateTime{}, offset) - when is_binary(address) and is_list(nodes) and is_integer(offset) and offset >= 0 do + def fetch_inputs_remotely(address, nodes, timestamp = %DateTime{}, offset, limit) + when is_binary(address) and is_list(nodes) and is_integer(offset) and offset >= 0 and + is_integer(limit) and limit >= 0 do conflict_resolver = fn results -> results |> Enum.sort_by(&length(&1.inputs), :desc) @@ -767,7 +773,7 @@ defmodule Archethic.TransactionChain do case P2P.quorum_read( nodes, - %GetTransactionInputs{address: address, offset: offset}, + %GetTransactionInputs{address: address, offset: offset, limit: limit}, conflict_resolver ) do {:ok, %TransactionInputList{inputs: inputs, more?: more?, offset: offset}} -> diff --git a/lib/archethic_web/graphql_schema/resolver.ex b/lib/archethic_web/graphql_schema/resolver.ex index 2294b9082..408e8cd09 100644 --- a/lib/archethic_web/graphql_schema/resolver.ex +++ b/lib/archethic_web/graphql_schema/resolver.ex @@ -125,7 +125,7 @@ defmodule ArchethicWeb.GraphQLSchema.Resolver do def get_inputs(address, paging_offset \\ 0, limit \\ 0) do inputs = address - |> Archethic.get_transaction_inputs(paging_offset) + |> Archethic.get_transaction_inputs(paging_offset, limit) |> Enum.map(&TransactionInput.to_map/1) case limit do