From 3cc3cbd6c7c907f33adfe3718e409241680e97bd Mon Sep 17 00:00:00 2001 From: EdwinGuayacan <80716239+EdwinGuayacan@users.noreply.github.com> Date: Tue, 20 Dec 2022 12:36:18 -0500 Subject: [PATCH] Local enpoint refactor --- lib/chainweb/pact.ex | 13 +- lib/chainweb/pact/endpoints.ex | 46 ------ lib/chainweb/pact/local.ex | 22 ++- lib/chainweb/pact/local_request_body.ex | 16 +- lib/chainweb/pact/spec.ex | 29 ++++ lib/types/local_request_body.ex | 54 ------ .../chainweb/pact/local_request_body_test.exs | 12 +- test/chainweb/pact/local_test.exs | 154 ++++++++++-------- test/support/fixtures/chainweb/local.json | 38 ++--- 9 files changed, 156 insertions(+), 228 deletions(-) delete mode 100644 lib/chainweb/pact/endpoints.ex create mode 100644 lib/chainweb/pact/spec.ex delete mode 100644 lib/types/local_request_body.ex diff --git a/lib/chainweb/pact.ex b/lib/chainweb/pact.ex index 3a21fcb9..129d79dc 100644 --- a/lib/chainweb/pact.ex +++ b/lib/chainweb/pact.ex @@ -1,13 +1,12 @@ defmodule Kadena.Chainweb.Pact do @moduledoc """ - Specifies the API for processing HTTP requests. + Exposes functions to interact with the Pact API endpoints. """ - alias Kadena.Chainweb.Pact.Local - defdelegate local(request, network \\ :testnet04, chain_id \\ "0"), to: Local, as: :process + alias Kadena.Chainweb.Pact.{Local, Send} - # defdelegate send(request, network \\ :test, chain_id \\ "0"), to: Send, as: :process - # defdelegate poll(request, network \\ :test, chain_id \\ "0"), to: Poll, as: :process - # defdelegate listen(request, network \\ :test, chain_id \\ "0"), to: Listen, as: :process - # defdelegate spv(request, network \\ :test, chain_id \\ "0"), to: SPV, as: :process + @default_network_opts [network_id: :testnet04, chain_id: 0] + + defdelegate send(cmds, network_opts \\ @default_network_opts), to: Send, as: :process + defdelegate local(cmds, network_opts \\ @default_network_opts), to: Local, as: :process end diff --git a/lib/chainweb/pact/endpoints.ex b/lib/chainweb/pact/endpoints.ex deleted file mode 100644 index 3fd24176..00000000 --- a/lib/chainweb/pact/endpoints.ex +++ /dev/null @@ -1,46 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Endpoints do - @moduledoc """ - Requests specification for `Chainweb.Pact` contracts. - """ - -<<<<<<< HEAD:lib/chainweb/pact/request.ex -======= - alias Kadena.Types.Command - alias Kadena.Types.CommandsList - - alias Kadena.Types.{ - Command, - CommandsList - } - ->>>>>>> 4e12645 (Add local endpoitn and PACT API):lib/chainweb/pact/endpoints.ex - alias Kadena.Chainweb.Pact.{ - ListenRequestBody, - ListenResponse, - LocalRequestBody, - LocalResponse, - PollRequestBody, - PollResponse, - SendRequestBody, - SendResponse, - SPVRequestBody, - SPVResponse - } - - @type network :: atom() - @type chain_id :: String.t() - @type error :: {:error, Keyword.t()} - @type body :: String.t() - @type request :: - Command.t() - | CommandsList.t() - @type response :: - ListenResponse.t() - | LocalResponse.t() - | PollResponse.t() - | SendResponse.t() - | SPVResponse.t() - - @callback process(request :: request(), network :: network(), chain_id :: chain_id()) :: - {:ok, response()} | error() -end diff --git a/lib/chainweb/pact/local.ex b/lib/chainweb/pact/local.ex index db30d8fd..ea41b2d1 100644 --- a/lib/chainweb/pact/local.ex +++ b/lib/chainweb/pact/local.ex @@ -4,36 +4,34 @@ defmodule Kadena.Chainweb.Pact.Local do """ alias Kadena.Chainweb.Request - alias Kadena.Chainweb.Pact.{Endpoints, JSONPayload, LocalResponse} - alias Kadena.Types.{Command, LocalRequestBody} + alias Kadena.Chainweb.Pact.{LocalRequestBody, LocalResponse, Spec} + alias Kadena.Types.Command @type cmd :: Command.t() - @type json_request_body :: String.t() - @behaviour Endpoints + @type json :: String.t() + @behaviour Spec @endpoint "local" @headers [{"Content-Type", "application/json"}] @impl true - def process(%Command{} = cmd, network, chain_id) do - request_body = get_json_request_body(cmd) + def process(%Command{} = cmd, network_id: network_id, chain_id: chain_id) do + request_body = json_request_body(cmd) :post |> Request.new(pact: [endpoint: @endpoint]) |> Request.set_chain_id(chain_id) - |> Request.set_network(network) + |> Request.set_network(network_id) |> Request.add_body(request_body) |> Request.add_headers(@headers) |> Request.perform() |> Request.results(as: LocalResponse) end - def process(_cmds, _network, _chain_id), do: {:error, [command: :invalid_command]} - - @spec get_json_request_body(cmd :: cmd()) :: json_request_body() - defp get_json_request_body(cmd) do + @spec json_request_body(cmd :: cmd()) :: json() + defp json_request_body(cmd) do cmd |> LocalRequestBody.new() - |> JSONPayload.parse() + |> LocalRequestBody.to_json!() end end diff --git a/lib/chainweb/pact/local_request_body.ex b/lib/chainweb/pact/local_request_body.ex index d2efea97..e6d5a5c1 100644 --- a/lib/chainweb/pact/local_request_body.ex +++ b/lib/chainweb/pact/local_request_body.ex @@ -7,7 +7,7 @@ defmodule Kadena.Chainweb.Pact.LocalRequestBody do @behaviour Kadena.Chainweb.Pact.Type - @type command :: String.t() + @type command :: Command.t() @type hash :: PactTransactionHash.t() @type sigs :: SignaturesList.t() @type cmd :: String.t() @@ -19,11 +19,8 @@ defmodule Kadena.Chainweb.Pact.LocalRequestBody do defstruct [:hash, :sigs, :cmd] @impl true - def new(args) do - args - |> Command.new() - |> build_local_request_body() - end + def new(%Command{} = cmd), do: build_local_request_body(cmd) + def(new(_cmd), do: {:error, [arg: :not_a_command]}) @impl true def to_json!(%__MODULE__{hash: hash, sigs: sigs, cmd: cmd}) do @@ -33,17 +30,12 @@ defmodule Kadena.Chainweb.Pact.LocalRequestBody do end end - @spec build_local_request_body(command :: command() | error()) :: t() | error() + @spec build_local_request_body(command :: command()) :: t() defp build_local_request_body(%Command{} = command) do attrs = Map.from_struct(command) struct(%__MODULE__{}, attrs) end - defp build_local_request_body({:error, [command: :not_a_list]}), - do: {:error, [local_request_body: :not_a_list]} - - defp build_local_request_body({:error, reason}), do: {:error, reason} - @spec to_signature_list(signatures :: sigs()) :: {:ok, raw_sigs()} defp to_signature_list(%SignaturesList{signatures: list}) do sigs = Enum.map(list, fn sig -> Map.from_struct(sig) end) diff --git a/lib/chainweb/pact/spec.ex b/lib/chainweb/pact/spec.ex new file mode 100644 index 00000000..47b38d19 --- /dev/null +++ b/lib/chainweb/pact/spec.ex @@ -0,0 +1,29 @@ +defmodule Kadena.Chainweb.Pact.Spec do + @moduledoc """ + Specifies the contracts to build the Pact's endpoints. + """ + + alias Kadena.Chainweb.Pact.{ + ListenResponse, + LocalResponse, + PollResponse, + SendResponse, + SPVResponse + } + + alias Kadena.Chainweb.Error + alias Kadena.Types.Command + + @type data :: list(Command.t()) | Command.t() + @type error :: {:error, Error.t()} + @type chain_id :: 0..19 | String.t() + @type network_opts :: [network_id: atom(), chain_id: chain_id()] + @type response :: + ListenResponse.t() + | LocalResponse.t() + | PollResponse.t() + | SendResponse.t() + | SPVResponse.t() + + @callback process(data :: data(), network_opts :: network_opts()) :: {:ok, response()} | error() +end diff --git a/lib/types/local_request_body.ex b/lib/types/local_request_body.ex deleted file mode 100644 index 2eeeb80b..00000000 --- a/lib/types/local_request_body.ex +++ /dev/null @@ -1,54 +0,0 @@ -defmodule Kadena.Types.LocalRequestBody do - @moduledoc """ - `LocalRequestBody` struct definition. - """ - - alias Kadena.Chainweb.Pact.JSONPayload - alias Kadena.Types.{Command, PactTransactionHash, SignaturesList} - - @behaviour Kadena.Types.Spec - - @type command :: Command.t() - @type hash :: PactTransactionHash.t() - @type sigs :: SignaturesList.t() - @type cmd :: String.t() - @type errors :: {:error, Keyword.t()} - - @type t :: %__MODULE__{hash: hash(), sigs: sigs(), cmd: cmd()} - - defstruct [:hash, :sigs, :cmd] - - @impl true - def new(%Command{} = command), do: build_local_request_body(command) - def new(_any), do: {:error, [arg: :not_a_command]} - - @spec build_local_request_body(command :: command()) :: t() - defp build_local_request_body(%Command{} = command) do - attrs = Map.from_struct(command) - struct(%__MODULE__{}, attrs) - end - - defimpl JSONPayload do - alias Kadena.Types.LocalRequestBody - alias Kadena.Utils.MapCase - - @type signatures_list :: SignaturesList.t() - @type signatures :: list(map()) - - @impl true - def parse(%LocalRequestBody{hash: hash, sigs: sigs, cmd: cmd}) do - with %PactTransactionHash{hash: hash} <- hash, - {:ok, sigs} <- to_signature_list(sigs) do - %{hash: hash, sigs: sigs, cmd: cmd} - |> MapCase.to_camel!() - |> Jason.encode!() - end - end - - @spec to_signature_list(signatures :: signatures_list()) :: {:ok, signatures()} - defp to_signature_list(%SignaturesList{signatures: list}) do - sigs = Enum.map(list, fn sig -> Map.from_struct(sig) end) - {:ok, sigs} - end - end -end diff --git a/test/chainweb/pact/local_request_body_test.exs b/test/chainweb/pact/local_request_body_test.exs index 082df61f..00f6f8ce 100644 --- a/test/chainweb/pact/local_request_body_test.exs +++ b/test/chainweb/pact/local_request_body_test.exs @@ -7,17 +7,12 @@ defmodule Kadena.Chainweb.Pact.LocalRequestBodyTest do alias Kadena.Chainweb.Pact.LocalRequestBody -<<<<<<< HEAD:test/chainweb/pact/local_request_body_test.exs - alias Kadena.Types.{PactTransactionHash, SignaturesList} -======= alias Kadena.Types.{ Command, - LocalRequestBody, PactTransactionHash, Signature, SignaturesList } ->>>>>>> 4e12645 (Add local endpoitn and PACT API):test/types/local_request_body_test.exs setup do cmd = @@ -93,15 +88,10 @@ defmodule Kadena.Chainweb.Pact.LocalRequestBodyTest do command: command, json_result: json_result } do -<<<<<<< HEAD:test/chainweb/pact/local_request_body_test.exs ^json_result = - [hash: hash, sigs: sigs, cmd: cmd] + command |> LocalRequestBody.new() |> LocalRequestBody.to_json!() -======= - local_request_body = LocalRequestBody.new(command) - ^json_result = JSONPayload.parse(local_request_body) ->>>>>>> 4e12645 (Add local endpoitn and PACT API):test/types/local_request_body_test.exs end end end diff --git a/test/chainweb/pact/local_test.exs b/test/chainweb/pact/local_test.exs index 2be9e8e4..8661a3fd 100644 --- a/test/chainweb/pact/local_test.exs +++ b/test/chainweb/pact/local_test.exs @@ -1,82 +1,102 @@ +defmodule Kadena.Chainweb.Client.CannedLocalRequests do + @moduledoc false + + alias Kadena.Test.Fixtures.Chainweb + + def request( + :post, + "https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/1/pact/api/v1/local", + _headers, + _body, + _options + ) do + response = Chainweb.fixture("local") + {:ok, response} + end +end + defmodule Kadena.Chainweb.Pact.LocalTest do + @moduledoc """ + `Local` endpoint implementation tests. + """ use ExUnit.Case - + alias Kadena.Chainweb.Client.CannedLocalRequests alias Kadena.Chainweb.Pact - - alias Kadena.Types.{ - Command, - PactTransactionHash, - Signature, - SignaturesList - } + alias Kadena.Chainweb.Pact.LocalResponse + alias Kadena.Cryptography + alias Kadena.Pact.ExecCommand + alias Kadena.Types.Metadata describe "process/3" do setup do - exec_command = %Command{ - cmd: - "{\"meta\":{\"chainId\":\"0\",\"creationTime\":1667249173,\"gasLimit\":1000,\"gasPrice\":1.0e-6,\"sender\":\"k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94\",\"ttl\":28800},\"networkId\":\"testnet04\",\"nonce\":\"2023-06-13 17:45:18.211131 UTC\",\"payload\":{\"exec\":{\"code\":\"(+ 5 6)\",\"data\":{}}},\"signers\":[{\"addr\":\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\",\"clist\":[{\"args\":[\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\"],\"name\":\"coin.GAS\"}],\"pubKey\":\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\",\"scheme\":\"ED25519\"}]}", - hash: %PactTransactionHash{ - hash: "-1npoTU2Mi71pKE_oteJiJuHuXTXxoObJm8zzVRK2pk" - }, - sigs: %SignaturesList{ - signatures: [ - %Signature{ - sig: - "8b234b83570359e52188cceb301036a2a7b255171e856fd550cac687a946f18fbfc0e769fd8393dda44d6d04c31b531eaf35efb3b78b5e40fd857a743133030d" - } - ] - } - } + Application.put_env(:kadena, :http_client_impl, CannedLocalRequests) + + on_exit(fn -> + Application.delete_env(:kadena, :http_client_impl) + end) + + network_id = :testnet04 + code = "(+ 5 6)" + nonce = "2023-06-13 17:45:18.211131 UTC" + + {:ok, keypair} = + Cryptography.KeyPair.from_secret_key( + "28834b7a0d6d1f84ae2c2efcb5b1de28122e07e2e4caad04a32988a3c79c547c" + ) + + meta_data = + MetaData.new( + creation_time: 1_671_462_208, + ttl: 28_800, + gas_limit: 1000, + gas_price: 1.0e-6, + sender: "k:d1a361d721cf81dbc21f676e6897f7e7a336671c0d5d25f87c10933cac6d8cf7", + chain_id: "1" + ) + + cmd = + ExecCommand.new() + |> ExecCommand.set_network(network_id) + |> ExecCommand.set_code(code) + |> ExecCommand.set_nonce(nonce) + |> ExecCommand.set_metadata(meta_data) + |> ExecCommand.add_keypair(keypair) + |> ExecCommand.build() %{ - exec_command: exec_command, - continuation: nil, - events: nil, - gas: 7, - logs: "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8", - meta_data: %{ - # block_height: 2_815_727, - # block_time: 1_671_054_330_981_668, - # prev_block_hash: "asisNr3nuU0t357i2bxMVUiIWDVHAMtncJHtmyENbio", - public_meta: %{ - chain_id: "0", - creation_time: 1_667_249_173, - gas_limit: 1000, - gas_price: 1.0e-6, - sender: "k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94", - ttl: 28_800 - } - }, - req_key: "-1npoTU2Mi71pKE_oteJiJuHuXTXxoObJm8zzVRK2pk", - result: %{data: 11, status: "success"}, - tx_id: nil + cmd: cmd, + local_response: + {:ok, + %LocalResponse{ + continuation: nil, + events: nil, + gas: 6, + logs: "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8", + meta_data: %{ + block_height: 3_303_861, + block_time: 1_671_546_034_831_940, + prev_block_hash: "Y6Wj0sxJpdV8M-3ihAbzUka57Wv5ZV2Uez6H_6_WeeY", + public_meta: %{ + chain_id: "1", + creation_time: 1_671_462_208, + gas_limit: 1000, + gas_price: 1.0e-6, + sender: "k:d1a361d721cf81dbc21f676e6897f7e7a336671c0d5d25f87c10933cac6d8cf7", + ttl: 28_800 + } + }, + req_key: "SvVzKL5KC0r1JdIkJDhMHT8vZhmO2CdTxPKX-6YmGG0", + result: %{data: 11, status: "success"}, + tx_id: nil + }} } end - test "with a exec Command", %{ - exec_command: exec_command, - continuation: continuation, - events: events, - gas: gas, - logs: logs, - meta_data: meta_data, - req_key: req_key, - result: result, - tx_id: tx_id + test "with an exec Command", %{ + cmd: cmd, + local_response: local_response } do - {:ok, response} = Pact.local(exec_command) - assert(continuation == response.continuation) - assert(events == response.events) - assert(gas == response.gas) - assert(logs == response.logs) - assert(meta_data.public_meta == response.meta_data.public_meta) - assert(req_key == response.req_key) - assert(result == response.result) - assert(tx_id == response.tx_id) - end - - test "with a invalid Command", %{} do - {:error, [command: :invalid_command]} = Pact.local(nil) + ^local_response = Pact.local(cmd, network_id: :testnet04, chain_id: 1) end end end diff --git a/test/support/fixtures/chainweb/local.json b/test/support/fixtures/chainweb/local.json index e32ac0db..31dd355c 100644 --- a/test/support/fixtures/chainweb/local.json +++ b/test/support/fixtures/chainweb/local.json @@ -1,24 +1,24 @@ { - "continuation": null, - "gas": 7, + "gas": 6, + "result": { + "status": "success", + "data": 11 + }, + "reqKey": "SvVzKL5KC0r1JdIkJDhMHT8vZhmO2CdTxPKX-6YmGG0", "logs": "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8", "metaData": { - "blockHeight": 2815727, - "blockTime": 1671054330981668, - "prevBlockHash": "asisNr3nuU0t357i2bxMVUiIWDVHAMtncJHtmyENbio", - "publicMeta": { - "chainId": "0", - "creationTime": 1667249173, - "gasLimit": 1000, - "gasPrice": 1.0e-6, - "sender": "k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94", - "ttl": 28800 - } - }, - "reqKey": "-1npoTU2Mi71pKE_oteJiJuHuXTXxoObJm8zzVRK2pk", - "result": { - "data": 11, - "status": "success" + "publicMeta": { + "creationTime": 1671462208, + "ttl": 28800, + "gasLimit": 1000, + "chainId": "1", + "gasPrice": 1.0e-6, + "sender": "k:d1a361d721cf81dbc21f676e6897f7e7a336671c0d5d25f87c10933cac6d8cf7" + }, + "blockTime": 1671546034831940, + "prevBlockHash": "Y6Wj0sxJpdV8M-3ihAbzUka57Wv5ZV2Uez6H_6_WeeY", + "blockHeight": 3303861 }, + "continuation": null, "txId": null -} +} \ No newline at end of file