From a3dab362f77dbca39fa56c7e79aac55a1dfa5a03 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 26 Oct 2020 17:49:39 +0300 Subject: [PATCH 01/11] create and check utxo --- priv/perf/apps/load_test/lib/runner/utxos.ex | 26 +++++ .../apps/load_test/lib/scenario/deposits.ex | 2 +- .../perf/apps/load_test/lib/scenario/utxos.ex | 105 ++++++++++++++++++ .../apps/load_test/lib/test_runner/config.ex | 7 +- .../apps/load_test/lib/watcher_info/utxo.ex | 41 +++++++ priv/perf/config/config.exs | 2 +- 6 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 priv/perf/apps/load_test/lib/runner/utxos.ex create mode 100644 priv/perf/apps/load_test/lib/scenario/utxos.ex create mode 100644 priv/perf/apps/load_test/lib/watcher_info/utxo.ex diff --git a/priv/perf/apps/load_test/lib/runner/utxos.ex b/priv/perf/apps/load_test/lib/runner/utxos.ex new file mode 100644 index 0000000000..a73d760281 --- /dev/null +++ b/priv/perf/apps/load_test/lib/runner/utxos.ex @@ -0,0 +1,26 @@ +# Copyright 2019-2020 OmiseGO Pte Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +defmodule LoadTest.Runner.Utxos do + @moduledoc """ + Utxos tests runner. + """ + use Chaperon.LoadTest + + def scenarios do + [ + {{1, LoadTest.Scenario.Utxos}, %{}} + ] + end +end diff --git a/priv/perf/apps/load_test/lib/scenario/deposits.ex b/priv/perf/apps/load_test/lib/scenario/deposits.ex index eaa24f23a8..cdcb04569a 100644 --- a/priv/perf/apps/load_test/lib/scenario/deposits.ex +++ b/priv/perf/apps/load_test/lib/scenario/deposits.ex @@ -63,7 +63,7 @@ defmodule LoadTest.Scenario.Deposits do session |> Session.add_metric("error_rate", 1) - |> Session.add_error(:test, error) + |> Session.add_error(:error, error) end end diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex new file mode 100644 index 0000000000..a7a4358ddf --- /dev/null +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -0,0 +1,105 @@ +# Copyright 2019-2020 OmiseGO Pte Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +defmodule LoadTest.Scenario.Utxos do + use Chaperon.Scenario + + alias Chaperon.Session + alias ExPlasma.Encoding + alias LoadTest.Ethereum.Account + alias LoadTest.Service.Faucet + alias LoadTest.WatcherInfo.Balance + alias LoadTest.WatcherInfo.Utxo + + @spec run(Session.t()) :: Session.t() + def run(session) do + tps = config(session, [:run_config, :tps]) + period_in_seconds = config(session, [:run_config, :period_in_seconds]) + + total_number_of_transactions = tps * period_in_seconds + period_in_mseconds = period_in_seconds * 1_000 + + session + |> cc_spread( + :create_utxos_and_make_assertions, + total_number_of_transactions, + period_in_mseconds + ) + |> await_all(:create_utxos_and_make_assertions) + end + + def create_utxos_and_make_assertions(session) do + with {:ok, sender, receiver} <- create_accounts(), + :ok <- fund_account(session, sender) do + # :ok <- spend_utxo(session, sender, receiver) do + Session.add_metric(session, "error_rate", 0) + else + error -> + log_error(session, "#{__MODULE__} failed with #{inspect(error)}") + + session + |> Session.add_metric("error_rate", 1) + |> Session.add_error(:error, error) + end + end + + defp create_accounts() do + {:ok, sender_address} = Account.new() + {:ok, receiver_address} = Account.new() + + {:ok, sender_address, receiver_address} + end + + defp fund_account(session, account) do + initial_amount = config(session, [:chain_config, :initial_amount]) + token = config(session, [:chain_config, :token]) + + with {:ok, utxo} <- fund_childchain_account(account, initial_amount, token), + :ok <- + fetch_childchain_balance(account, + amount: initial_amount, + token: Encoding.to_binary(token), + error: :wrong_childchain_after_funding + ), + :ok <- validate_utxo(account, token, initial_amount) do + {:ok, utxo} + end + end + + defp fund_childchain_account(address, amount, token) do + case Faucet.fund_child_chain_account(address, amount, token) do + {:ok, utxo} -> {:ok, utxo} + _ -> :failed_to_fund_childchain_account + end + end + + defp fetch_childchain_balance(account, amount: amount, token: token, error: error) do + childchain_balance = Balance.fetch_balance(account.addr, amount, token) + + case childchain_balance["amount"] do + ^amount -> :ok + _ -> error + end + end + + defp validate_utxo(account, currency, amount) do + {:ok, result} = Utxo.get_utxos(account) + string_account = Encoding.to_hex(account.addr) + + case result["data"] do + [%{"amount" => ^amount, "currency" => ^currency, "owner" => ^string_account}] -> :ok + _ -> :invalid_utxos + end + end +end diff --git a/priv/perf/apps/load_test/lib/test_runner/config.ex b/priv/perf/apps/load_test/lib/test_runner/config.ex index 857d666974..d299ae39b7 100644 --- a/priv/perf/apps/load_test/lib/test_runner/config.ex +++ b/priv/perf/apps/load_test/lib/test_runner/config.ex @@ -19,7 +19,8 @@ defmodule LoadTest.TestRunner.Config do alias ExPlasma.Encoding @tests %{ - "deposits" => LoadTest.Runner.Deposits + "deposits" => LoadTest.Runner.Deposits, + "utxos" => LoadTest.Runner.Utxos } @configs %{ @@ -29,6 +30,10 @@ defmodule LoadTest.TestRunner.Config do deposited_amount: 200_000_000_000_000_000, transferred_amount: 100_000_000_000_000_000, gas_price: 2_000_000_000 + }, + "utxos" => %{ + token: "0x0000000000000000000000000000000000000000", + initial_amount: 760 } } diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex new file mode 100644 index 0000000000..9d70b2a77d --- /dev/null +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -0,0 +1,41 @@ +# Copyright 2019-2020 OmiseGO Pte Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.w + +defmodule LoadTest.WatcherInfo.Utxo do + require Logger + + alias LoadTest.Connection.WatcherInfo + alias LoadTest.Utils.Encoding + alias LoadTest.Service.Sync + + @poll_timeout 60_000 + + def get_utxos(sender) do + {:ok, response} = + Sync.repeat_until_success( + fn -> + WatcherInfoAPI.Api.Account.account_get_utxos( + WatcherInfo.client(), + %WatcherInfoAPI.Model.AddressBodySchema1{ + address: Encoding.to_hex(sender.addr) + } + ) + end, + @poll_timeout, + "Failes to fetch utxos" + ) + + {:ok, Jason.decode!(response.body)} + end +end diff --git a/priv/perf/config/config.exs b/priv/perf/config/config.exs index aad0cb0595..0068aca0c9 100644 --- a/priv/perf/config/config.exs +++ b/priv/perf/config/config.exs @@ -28,7 +28,7 @@ config :load_test, erc20_vault_address: System.get_env("CONTRACT_ADDRESS_ERC20_VAULT"), test_currency: "0x0000000000000000000000000000000000000000", faucet_deposit_amount: trunc(:math.pow(10, 14)), - fee_amount: 1, + fee_amount: 75, deposit_finality_margin: 10, gas_price: 2_000_000_000 From a14b04c76872d641d01ff143971dd7c9e7035097 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 26 Oct 2020 18:13:51 +0300 Subject: [PATCH 02/11] spend utxo --- priv/perf/apps/load_test/lib/scenario/utxos.ex | 13 +++++++++++-- priv/perf/apps/load_test/lib/test_runner/config.ex | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex index a7a4358ddf..8510edb725 100644 --- a/priv/perf/apps/load_test/lib/scenario/utxos.ex +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -17,6 +17,7 @@ defmodule LoadTest.Scenario.Utxos do alias Chaperon.Session alias ExPlasma.Encoding + alias LoadTest.ChildChain.Transaction alias LoadTest.Ethereum.Account alias LoadTest.Service.Faucet alias LoadTest.WatcherInfo.Balance @@ -41,8 +42,8 @@ defmodule LoadTest.Scenario.Utxos do def create_utxos_and_make_assertions(session) do with {:ok, sender, receiver} <- create_accounts(), - :ok <- fund_account(session, sender) do - # :ok <- spend_utxo(session, sender, receiver) do + {:ok, utxo} <- fund_account(session, sender), + :ok <- spend_utxo(session, utxo, sender, receiver) do Session.add_metric(session, "error_rate", 0) else error -> @@ -102,4 +103,12 @@ defmodule LoadTest.Scenario.Utxos do _ -> :invalid_utxos end end + + defp spend_utxo(session, utxo, sender, receiver) do + amount = config(session, [:chain_config, :initial_amount]) + token = config(session, [:chain_config, :token]) + fee = config(session, [:chain_config, :fee]) + + Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token) + end end diff --git a/priv/perf/apps/load_test/lib/test_runner/config.ex b/priv/perf/apps/load_test/lib/test_runner/config.ex index d299ae39b7..939c5aa586 100644 --- a/priv/perf/apps/load_test/lib/test_runner/config.ex +++ b/priv/perf/apps/load_test/lib/test_runner/config.ex @@ -33,7 +33,8 @@ defmodule LoadTest.TestRunner.Config do }, "utxos" => %{ token: "0x0000000000000000000000000000000000000000", - initial_amount: 760 + initial_amount: 760, + fee: 75 } } From e73959124b5c3bc003bcdfa1ea74a016a585d01c Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Mon, 26 Oct 2020 18:53:32 +0300 Subject: [PATCH 03/11] assert balances after spending --- .../perf/apps/load_test/lib/scenario/utxos.ex | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex index 8510edb725..5cf9df11c6 100644 --- a/priv/perf/apps/load_test/lib/scenario/utxos.ex +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -85,15 +85,6 @@ defmodule LoadTest.Scenario.Utxos do end end - defp fetch_childchain_balance(account, amount: amount, token: token, error: error) do - childchain_balance = Balance.fetch_balance(account.addr, amount, token) - - case childchain_balance["amount"] do - ^amount -> :ok - _ -> error - end - end - defp validate_utxo(account, currency, amount) do {:ok, result} = Utxo.get_utxos(account) string_account = Encoding.to_hex(account.addr) @@ -109,6 +100,20 @@ defmodule LoadTest.Scenario.Utxos do token = config(session, [:chain_config, :token]) fee = config(session, [:chain_config, :fee]) - Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token) + with _ <- Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token), + :ok <- fetch_childchain_balance(sender, amount: 0, token: token, error: :wrong_sender_balance), + :ok <- fetch_childchain_balance(receiver, amount: amount - fee, token: token, error: :wrong_receiver_balance) do + :ok + end + end + + defp fetch_childchain_balance(account, amount: amount, token: token, error: error) do + childchain_balance = Balance.fetch_balance(account.addr, amount, token) + + case childchain_balance do + nil when amount == 0 -> :ok + %{"amount" => ^amount} -> :ok + _ -> error + end end end From dbac9c22935287998041a9c044a177cf8a812fc0 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 17:10:01 +0300 Subject: [PATCH 04/11] validate exact utxos --- .../perf/apps/load_test/lib/scenario/utxos.ex | 32 ++++--- .../apps/load_test/lib/watcher_info/utxo.ex | 85 +++++++++++++++---- 2 files changed, 86 insertions(+), 31 deletions(-) diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex index 5cf9df11c6..1eab52a1b4 100644 --- a/priv/perf/apps/load_test/lib/scenario/utxos.ex +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -73,11 +73,24 @@ defmodule LoadTest.Scenario.Utxos do token: Encoding.to_binary(token), error: :wrong_childchain_after_funding ), - :ok <- validate_utxo(account, token, initial_amount) do + :ok <- validate_utxos(account, %{utxo | owner: account.addr}) do {:ok, utxo} end end + defp validate_utxos(account, utxo) do + utxo_with_owner = + case utxo do + :empty -> :empty + _ -> %{utxo | owner: account.addr} + end + + case Utxo.get_utxos(account, utxo_with_owner) do + {:ok, _} -> :ok + _other -> :invalid_utxos + end + end + defp fund_childchain_account(address, amount, token) do case Faucet.fund_child_chain_account(address, amount, token) do {:ok, utxo} -> {:ok, utxo} @@ -85,24 +98,15 @@ defmodule LoadTest.Scenario.Utxos do end end - defp validate_utxo(account, currency, amount) do - {:ok, result} = Utxo.get_utxos(account) - string_account = Encoding.to_hex(account.addr) - - case result["data"] do - [%{"amount" => ^amount, "currency" => ^currency, "owner" => ^string_account}] -> :ok - _ -> :invalid_utxos - end - end - defp spend_utxo(session, utxo, sender, receiver) do amount = config(session, [:chain_config, :initial_amount]) token = config(session, [:chain_config, :token]) fee = config(session, [:chain_config, :fee]) - with _ <- Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token), - :ok <- fetch_childchain_balance(sender, amount: 0, token: token, error: :wrong_sender_balance), - :ok <- fetch_childchain_balance(receiver, amount: amount - fee, token: token, error: :wrong_receiver_balance) do + with [new_utxo] <- Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token), + :ok <- validate_utxos(sender, :empty), + :ok <- validate_utxos(receiver, %{new_utxo | owner: receiver.addr}), + :ok <- fetch_childchain_balance(sender, amount: 0, token: token, error: :wrong_sender_balance) do :ok end end diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index 9d70b2a77d..1080834355 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -16,26 +16,77 @@ defmodule LoadTest.WatcherInfo.Utxo do require Logger alias LoadTest.Connection.WatcherInfo - alias LoadTest.Utils.Encoding alias LoadTest.Service.Sync + alias LoadTest.Utils.Encoding @poll_timeout 60_000 - def get_utxos(sender) do - {:ok, response} = - Sync.repeat_until_success( - fn -> - WatcherInfoAPI.Api.Account.account_get_utxos( - WatcherInfo.client(), - %WatcherInfoAPI.Model.AddressBodySchema1{ - address: Encoding.to_hex(sender.addr) - } - ) - end, - @poll_timeout, - "Failes to fetch utxos" - ) - - {:ok, Jason.decode!(response.body)} + def get_utxos(sender, utxo \\ nil) do + Sync.repeat_until_success( + fn -> + fetch_utxos(sender, utxo) + end, + @poll_timeout, + "Failed to fetch utxos" + ) + end + + defp fetch_utxos(sender, utxo) do + case WatcherInfoAPI.Api.Account.account_get_utxos( + WatcherInfo.client(), + %WatcherInfoAPI.Model.AddressBodySchema1{ + address: Encoding.to_hex(sender.addr) + } + ) do + {:ok, result} -> + decoded_response = Jason.decode!(result.body) + + case utxo do + nil -> + {:ok, decoded_response} + + :empty -> + case decoded_response["data"] do + [] -> {:ok, []} + other -> {:error, other} + end + + _data -> + find_utxo(decoded_response, utxo) + end + + other -> + other + end + end + + defp find_utxo(response, utxo) do + found_utxo = + Enum.find(response["data"], fn %{ + "amount" => amount, + "blknum" => blknum, + "currency" => currency, + "oindex" => oindex, + "otype" => otype, + "owner" => owner, + "txindex" => txindex + } -> + current_utxo = %ExPlasma.Utxo{ + amount: amount, + blknum: blknum, + currency: Encoding.to_binary(currency), + oindex: oindex, + output_type: otype, + owner: Encoding.to_binary(owner), + txindex: txindex + } + + current_utxo == utxo + end) + + case found_utxo do + nil -> {:error, response} + _ -> {:ok, found_utxo} + end end end From 62d343c873ea1eeaa65ec9c59fee7ab5632cf749 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 18:11:19 +0300 Subject: [PATCH 05/11] fix token encoding --- priv/perf/apps/load_test/lib/scenario/utxos.ex | 12 ++++++++++-- priv/perf/config/config.exs | 10 +++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex index 1eab52a1b4..7f71a2242a 100644 --- a/priv/perf/apps/load_test/lib/scenario/utxos.ex +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -102,11 +102,19 @@ defmodule LoadTest.Scenario.Utxos do amount = config(session, [:chain_config, :initial_amount]) token = config(session, [:chain_config, :token]) fee = config(session, [:chain_config, :fee]) + amount_to_transfer = amount - fee - with [new_utxo] <- Transaction.spend_utxo(utxo, amount - fee, fee, sender, receiver, token), + with [new_utxo] <- Transaction.spend_utxo(utxo, amount_to_transfer, fee, sender, receiver, token), :ok <- validate_utxos(sender, :empty), :ok <- validate_utxos(receiver, %{new_utxo | owner: receiver.addr}), - :ok <- fetch_childchain_balance(sender, amount: 0, token: token, error: :wrong_sender_balance) do + :ok <- + fetch_childchain_balance(sender, amount: 0, token: Encoding.to_binary(token), error: :wrong_sender_balance), + :ok <- + fetch_childchain_balance(receiver, + amount: amount_to_transfer, + token: Encoding.to_binary(token), + error: :wrong_sender_balance + ) do :ok end end diff --git a/priv/perf/config/config.exs b/priv/perf/config/config.exs index 0068aca0c9..f9502051ec 100644 --- a/priv/perf/config/config.exs +++ b/priv/perf/config/config.exs @@ -14,7 +14,7 @@ config :ethereumex, config :load_test, pool_size: 5000, max_connection: 5000, - retry_sleep: System.get_env("RETRY_SLEEP") || 1_000, + retry_sleep: "RETRY_SLEEP" |> System.get_env("1000") |> String.to_integer(), child_chain_url: System.get_env("CHILD_CHAIN_URL") || "http://localhost:9656", watcher_security_url: System.get_env("WATCHER_SECURITY_URL") || "http://localhost:7434", watcher_info_url: System.get_env("WATCHER_INFO_URL") || "http://localhost:7534", @@ -23,14 +23,14 @@ config :load_test, "0xd885a307e35738f773d8c9c63c7a3f3977819274638d04aaf934a1e1158513ce", eth_vault_address: System.get_env("CONTRACT_ADDRESS_ETH_VAULT"), contract_address_payment_exit_game: System.get_env("CONTRACT_ADDRESS_PAYMENT_EXIT_GAME"), - child_block_interval: 1000, + child_block_interval: "CHILD_BLOCK_INTERVAL" |> System.get_env("1000") |> String.to_integer(), contract_address_plasma_framework: System.get_env("CONTRACT_ADDRESS_PLASMA_FRAMEWORK"), erc20_vault_address: System.get_env("CONTRACT_ADDRESS_ERC20_VAULT"), test_currency: "0x0000000000000000000000000000000000000000", faucet_deposit_amount: trunc(:math.pow(10, 14)), - fee_amount: 75, - deposit_finality_margin: 10, - gas_price: 2_000_000_000 + fee_amount: "FEE_AMOUNT" |> System.get_env("75") |> String.to_integer(), + deposit_finality_margin: "DEPOSIT_FINALITY_MARGIN" |> System.get_env("10") |> String.to_integer(), + gas_price: "GAS_PRICE" |> System.get_env("2000000000") |> String.to_integer() config :ex_plasma, eip_712_domain: [ From 7f73e55c98dbfe82bb3e5ab9e30496c8aec7a37c Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 19:10:49 +0300 Subject: [PATCH 06/11] add test to run on ci --- .../perf/apps/load_test/lib/scenario/utxos.ex | 10 +++++ .../load_test/lib/watcher_info/balance.ex | 2 +- .../apps/load_test/lib/watcher_info/utxo.ex | 37 +++++++++------- .../test/load_tests/runner/utxos_test.exs | 42 +++++++++++++++++++ 4 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 priv/perf/apps/load_test/test/load_tests/runner/utxos_test.exs diff --git a/priv/perf/apps/load_test/lib/scenario/utxos.ex b/priv/perf/apps/load_test/lib/scenario/utxos.ex index 7f71a2242a..c4b4243b35 100644 --- a/priv/perf/apps/load_test/lib/scenario/utxos.ex +++ b/priv/perf/apps/load_test/lib/scenario/utxos.ex @@ -13,6 +13,16 @@ # limitations under the License. defmodule LoadTest.Scenario.Utxos do + @moduledoc """ + The scenario for utxos tests: + + 1. It creates two accounts: the sender and the receiver. + 2. It funds sender with the specified amount on the childchain, checks utxos and balance. + 3. The sender account sends the specifed amount on the childchain to the receiver, + checks its balance on the childchain and utxos for both accounts. + + """ + use Chaperon.Scenario alias Chaperon.Session diff --git a/priv/perf/apps/load_test/lib/watcher_info/balance.ex b/priv/perf/apps/load_test/lib/watcher_info/balance.ex index 2383c70de5..9aed23d8b9 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/balance.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/balance.ex @@ -14,7 +14,7 @@ defmodule LoadTest.WatcherInfo.Balance do @moduledoc """ - Functions related to balanes on the childchain + Functions related to balances on the childchain """ require Logger diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index 1080834355..4950382917 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -13,14 +13,19 @@ # limitations under the License.w defmodule LoadTest.WatcherInfo.Utxo do + @moduledoc """ + Functions for retrieving utxos through WatcherInfo API. + """ require Logger alias LoadTest.Connection.WatcherInfo + alias LoadTest.Ethereum.Account alias LoadTest.Service.Sync alias LoadTest.Utils.Encoding @poll_timeout 60_000 + @spec get_utxos(Account.addr_t(), ExPlasma.Utxo.t() | nil | :empty) :: {:ok, [] | ExPlasma.Utxo.t()} | no_return def get_utxos(sender, utxo \\ nil) do Sync.repeat_until_success( fn -> @@ -39,28 +44,32 @@ defmodule LoadTest.WatcherInfo.Utxo do } ) do {:ok, result} -> - decoded_response = Jason.decode!(result.body) + result.body + |> Jason.decode!() + |> find_utxo(utxo) - case utxo do - nil -> - {:ok, decoded_response} + other -> + other + end + end - :empty -> - case decoded_response["data"] do - [] -> {:ok, []} - other -> {:error, other} - end + defp find_utxo(decoded_response, utxo) do + case utxo do + nil -> + {:ok, decoded_response} - _data -> - find_utxo(decoded_response, utxo) + :empty -> + case decoded_response["data"] do + [] -> {:ok, []} + other -> {:error, other} end - other -> - other + _data -> + do_find_utxo(decoded_response, utxo) end end - defp find_utxo(response, utxo) do + defp do_find_utxo(response, utxo) do found_utxo = Enum.find(response["data"], fn %{ "amount" => amount, diff --git a/priv/perf/apps/load_test/test/load_tests/runner/utxos_test.exs b/priv/perf/apps/load_test/test/load_tests/runner/utxos_test.exs new file mode 100644 index 0000000000..7a352feb57 --- /dev/null +++ b/priv/perf/apps/load_test/test/load_tests/runner/utxos_test.exs @@ -0,0 +1,42 @@ +# Copyright 2019-2020 OmiseGO Pte Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +defmodule LoadTest.Runner.UtxosTest do + use ExUnit.Case + + @moduletag :utxos + + test "deposits test" do + token = "0x0000000000000000000000000000000000000000" + initial_amount = 760 + fee = 75 + + config = %{ + chain_config: %{ + token: token, + initial_amount: initial_amount, + fee: fee + }, + run_config: %{ + tps: 1, + period_in_seconds: 20 + }, + timeout: :infinity + } + + result = Chaperon.run_load_test(LoadTest.Runner.Utxos, config: config) + + assert result.metrics["error_rate"][:mean] == 0.0 + end +end From e3eedd830b85940bf7826d3167e824ac2f09045f Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 21:21:30 +0300 Subject: [PATCH 07/11] Update priv/perf/apps/load_test/lib/watcher_info/utxo.ex Co-authored-by: Ino Murko --- priv/perf/apps/load_test/lib/watcher_info/utxo.ex | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index 4950382917..0fb2a838ee 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -37,12 +37,10 @@ defmodule LoadTest.WatcherInfo.Utxo do end defp fetch_utxos(sender, utxo) do - case WatcherInfoAPI.Api.Account.account_get_utxos( - WatcherInfo.client(), - %WatcherInfoAPI.Model.AddressBodySchema1{ - address: Encoding.to_hex(sender.addr) - } - ) do +client = WatcherInfo.client() +body = %WatcherInfoAPI.Model.AddressBodySchema1{address: Encoding.to_hex(sender.addr} +account_utxos = WatcherInfoAPI.Api.Account.account_get_utxos(client, body) + case account_utxos do {:ok, result} -> result.body |> Jason.decode!() From 171d0945276035dc817a5b7210f41853c694871b Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 21:21:50 +0300 Subject: [PATCH 08/11] Update priv/perf/apps/load_test/lib/watcher_info/utxo.ex Co-authored-by: Ino Murko --- .../apps/load_test/lib/watcher_info/utxo.ex | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index 0fb2a838ee..7715eb7ed2 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -51,20 +51,17 @@ account_utxos = WatcherInfoAPI.Api.Account.account_get_utxos(client, body) end end - defp find_utxo(decoded_response, utxo) do - case utxo do - nil -> - {:ok, decoded_response} - - :empty -> - case decoded_response["data"] do - [] -> {:ok, []} - other -> {:error, other} - end - - _data -> - do_find_utxo(decoded_response, utxo) - end + defp find_utxo(decoded_response, nil) do + {:ok, decoded_response} + end + defp find_utxo(%{"data" => []}, :empty) do +{:ok, []} + end + defp find_utxo(decoded_response, :empty) do + {:error, decoded_response} + end + defp find_utxo(decoded_response, _utxo) do +do_find_utxo(decoded_response, utxo) end defp do_find_utxo(response, utxo) do From 3e4bac1539981eb6c33dd7c0822262eace5e98ba Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 27 Oct 2020 21:29:31 +0300 Subject: [PATCH 09/11] mix format --- .../apps/load_test/lib/watcher_info/utxo.ex | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index 7715eb7ed2..fee0478113 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -37,9 +37,10 @@ defmodule LoadTest.WatcherInfo.Utxo do end defp fetch_utxos(sender, utxo) do -client = WatcherInfo.client() -body = %WatcherInfoAPI.Model.AddressBodySchema1{address: Encoding.to_hex(sender.addr} -account_utxos = WatcherInfoAPI.Api.Account.account_get_utxos(client, body) + client = WatcherInfo.client() + body = %WatcherInfoAPI.Model.AddressBodySchema1{address: Encoding.to_hex(sender.addr)} + account_utxos = WatcherInfoAPI.Api.Account.account_get_utxos(client, body) + case account_utxos do {:ok, result} -> result.body @@ -52,16 +53,19 @@ account_utxos = WatcherInfoAPI.Api.Account.account_get_utxos(client, body) end defp find_utxo(decoded_response, nil) do - {:ok, decoded_response} + {:ok, decoded_response} end + defp find_utxo(%{"data" => []}, :empty) do -{:ok, []} + {:ok, []} end + defp find_utxo(decoded_response, :empty) do - {:error, decoded_response} + {:error, decoded_response} end + defp find_utxo(decoded_response, _utxo) do -do_find_utxo(decoded_response, utxo) + do_find_utxo(decoded_response, utxo) end defp do_find_utxo(response, utxo) do From 2f200a6b74b22fc637058f3c37c0649687046823 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 28 Oct 2020 12:23:15 +0300 Subject: [PATCH 10/11] fix build --- priv/perf/apps/load_test/lib/watcher_info/utxo.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex index fee0478113..da3280c068 100644 --- a/priv/perf/apps/load_test/lib/watcher_info/utxo.ex +++ b/priv/perf/apps/load_test/lib/watcher_info/utxo.ex @@ -64,7 +64,7 @@ defmodule LoadTest.WatcherInfo.Utxo do {:error, decoded_response} end - defp find_utxo(decoded_response, _utxo) do + defp find_utxo(decoded_response, utxo) do do_find_utxo(decoded_response, utxo) end From 0c4b12d904e476b19267feeee9b9f58de15f747e Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 28 Oct 2020 18:12:47 +0300 Subject: [PATCH 11/11] add cli help command for the perf project --- priv/perf/apps/load_test/lib/test_runner.ex | 8 +- .../apps/load_test/lib/test_runner/config.ex | 39 +++-- .../apps/load_test/lib/test_runner/help.ex | 144 ++++++++++++++++++ 3 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 priv/perf/apps/load_test/lib/test_runner/help.ex diff --git a/priv/perf/apps/load_test/lib/test_runner.ex b/priv/perf/apps/load_test/lib/test_runner.ex index 6299cf3aeb..2703583c18 100644 --- a/priv/perf/apps/load_test/lib/test_runner.ex +++ b/priv/perf/apps/load_test/lib/test_runner.ex @@ -36,7 +36,13 @@ defmodule LoadTest.TestRunner do alias LoadTest.TestRunner.Config def run() do - {runner_module, config, property} = Config.parse() + case Config.parse() do + {:ok, {runner_module, config, property}} -> run_test(runner_module, config, property) + :ok -> :ok + end + end + + defp run_test(runner_module, config, property) do result = Chaperon.run_load_test(runner_module, print_results: true, config: config) # / 1 is to convert result to float (mean is float, percentiles are integers)[O diff --git a/priv/perf/apps/load_test/lib/test_runner/config.ex b/priv/perf/apps/load_test/lib/test_runner/config.ex index 939c5aa586..f9e1808d8c 100644 --- a/priv/perf/apps/load_test/lib/test_runner/config.ex +++ b/priv/perf/apps/load_test/lib/test_runner/config.ex @@ -17,6 +17,7 @@ defmodule LoadTest.TestRunner.Config do Command line args parser for TestRunner. """ alias ExPlasma.Encoding + alias LoadTest.TestRunner.Help @tests %{ "deposits" => LoadTest.Runner.Deposits, @@ -39,27 +40,33 @@ defmodule LoadTest.TestRunner.Config do } def parse() do - [test, rate, period, property] = - case System.argv() do - [test, rate, period] -> - [test, rate, period, :mean] + case System.argv() do + [test, rate, period] -> + {:ok, config(test, rate, period, :mean)} - [test, rate, period, percentile] -> - percentile = parse_percentile(percentile) - [test, rate, period, percentile] - end + [test, rate, period, percentile] -> + percentile = parse_percentile(percentile) + {:ok, config(test, rate, period, percentile)} - rate_int = String.to_integer(rate) - period_int = String.to_integer(period) + ["help"] -> + Help.help() - config = config(test, rate_int, period_int) + ["help", "env"] -> + Help.help("env") - runner_module = Map.fetch!(@tests, test) + ["help", name] -> + Help.help(name) - {runner_module, config, property} + :ok + end end - defp config(test, rate_int, period_int) do + defp config(test, rate, period, property) do + rate_int = String.to_integer(rate) + period_int = String.to_integer(period) + + runner_module = Map.fetch!(@tests, test) + # Chaperon's SpreadAsyns (https://github.com/polleverywhere/chaperon/blob/13cc4a2d2a7baacddf20c46397064b5e42a48d97/lib/chaperon/action/spread_async.ex) # spawns a separate process for each execution. VM may fail if too many processes are spawned if rate_int * period_int > 200_000, do: raise("too many processes") @@ -71,11 +78,13 @@ defmodule LoadTest.TestRunner.Config do chain_config = read_config!(test) - %{ + config = %{ run_config: run_config, chain_config: chain_config, timeout: :infinity } + + {runner_module, config, property} end defp read_config!(test) do diff --git a/priv/perf/apps/load_test/lib/test_runner/help.ex b/priv/perf/apps/load_test/lib/test_runner/help.ex new file mode 100644 index 0000000000..d189f8bb0e --- /dev/null +++ b/priv/perf/apps/load_test/lib/test_runner/help.ex @@ -0,0 +1,144 @@ +# Copyright 2019-2020 OmiseGO Pte Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +defmodule LoadTest.TestRunner.Help do + @moduledoc """ + Shows help info for TestRunner. + """ + + require Logger + + @help """ + + `LoadTest.TestRunner` accepts three required parameters: + + 1. Test name (`utxos` or `deposits`) + 2. Rate in tests per second + 3. Period in seconds + + For example, if you want to run `deposits` with 5 tests / second rate over 20 seconds, you + should run the following command: + + ``` + mix run -e "LoadTest.TestRunner.run()" -- deposits 5 20 + ``` + + To modify tests values use `TEST_CONFIG_PATH`. It should contain a path to json file containing + test values: + + ``` + TEST_CONFIG_PATH=./my_file mix run -e "LoadTest.TestRunner.run()" -- deposits 1 5 + ``` + + To see which values can be overridden, use + + ``` + mix run -e "LoadTest.TestRunner.run()" -- help test_name + ``` + + To see env variable, use: + + ``` + mix run -e "LoadTest.TestRunner.run()" -- help env + ``` + """ + + @help_test %{ + "deposits" => """ + + A single iteration of this test consists of the following steps: + + 1. It creates two accounts: the depositor and the receiver. + 2. It funds depositor with the specified amount (`initial_amount`) on the rootchain. + 3. It creates deposit (`deposited_amount`) with gas price `gas_price` for the depositor account on the childchain and + checks balances on the rootchain and the childchain after this deposit. + 4. The depositor account sends the specifed amount (`transferred_amount`) on the childchain to the receiver + and checks its balance on the childchain. + + Overridable parameters are: + + - token. default value is "0x0000000000000000000000000000000000000000" + - initial_amount. default value is 500_000_000_000_000_000 + - deposited_amount default value is 200_000_000_000_000_000 + - transferred_amount. default value is 100_000_000_000_000_000 + - gas_price. default value is 2_000_000_000 + """, + "utxos" => """ + + A single iteration of this test consists of the following steps: + + 1.1 Two accounts are created - the sender and the receiver + + 2.1 The sender account is funded with `initial_amount` `token` + 2.2 The balance on the childchain of the sender is validated using WatcherInfoAPI.Api.Account.account_get_balance API. + 2.3 Utxos of the sender are validated using WatcherInfoAPI.Api.Account.account_get_utxos API + + 3.1 The sender sends all his tokens to the receiver with fee `fee` + 3.2 The balance on the childchain of the sender is validated + 3.3 The balance on the childchain of the receiver is validated + 3.4 Utxos of the sender are validated + 3.5 Utxos of the receiver are validated + + Overridable parameters are: + + - initial_balance. default value is 760 + - token. default value is "0x0000000000000000000000000000000000000000" + - fee. default value is 75 + """ + } + + @env """ + + ETHEREUM_RPC_URL - Ethereum Json RPC url. Default value is http://localhost:8545 + RETRY_SLEEP - Sleeping period used when polling data. Default value is 1000 (ms) + CHILD_CHAIN_URL - Childcahin url. Default value is http://localhost:9656 + WATCHER_SECURITY_URL - Watcher security url. Default value is http://localhost:7434 + WATCHER_INFO_URL - Watcehr info url. Default value is http://localhost:7534 + LOAD_TEST_FAUCET_PRIVATE_KEY - Faucet private key. Default value is 0xd885a307e35738f773d8c9c63c7a3f3977819274638d04aaf934a1e1158513ce + CONTRACT_ADDRESS_ETH_VAULT - Eth vault contact address + CONTRACT_ADDRESS_PAYMENT_EXIT_GAME - Payment exit game contract address + CHILD_BLOCK_INTERVAL - Block generation interval. Default value is 1000 (ms) + CONTRACT_ADDRESS_PLASMA_FRAMEWORK - Plasma framework contract address + CONTRACT_ADDRESS_ERC20_VAULT - Erc 20 vault contract address + FEE_AMOUNT - Fee amount used by faucet when funding accounts. Default value is 75 + DEPOSIT_FINALITY_MARGIN - Number of comfirmation for a deposit. Default value is 10 + """ + + def help do + IO.puts(@help) + end + + def help("env") do + IO.puts(@env) + end + + def help(test_name) do + case @help_test[test_name] do + nil -> + tests = + @help_test + |> Map.keys() + |> Enum.join(", ") + + IO.puts(""" + + Documentation for `#{test_name}` is not found. Available tests are #{tests}. + + """) + + doc -> + IO.puts(doc) + end + end +end