diff --git a/README.md b/README.md index a74a6c8..7dd62fb 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,11 @@ make test # To run a specific test, see the in apps/itest/test/ mix test test/itest/.exs ``` + +## CI flow + +If you made a change in repo that requires e2e test (`elixir-omg` is used as an example here): +1. Code the test and open PR in `specs` repo. +3. Edit `.gitmodules` to change the `specs` repo in `elixir-omg` to point to your `specs` PR branch. +4. Before you merge `elixir-omg` PR, change the `specs` repo back to master. +5. Merge the PR in `specs` repo. \ No newline at end of file diff --git a/apps/itest/lib/in_flight_exit_client.ex b/apps/itest/lib/in_flight_exit_client.ex new file mode 100644 index 0000000..8528d88 --- /dev/null +++ b/apps/itest/lib/in_flight_exit_client.ex @@ -0,0 +1,43 @@ +# 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 Itest.InFlightExitClient do + @moduledoc """ + Implements in-flight exit related actions. + """ + alias Itest.Transactions.Encoding + + import Itest.Poller, only: [wait_on_receipt_confirmed: 1] + + require Logger + + @gas 540_000 + + def delete_in_flight_exit(owner, exit_game_contract_address, exit_id) do + _ = Logger.info("Deleting in-flight exit.") + + data = ABI.encode("deleteNonPiggybackedInFlightExit(uint160)", [exit_id]) + + tx = %{ + from: owner, + to: exit_game_contract_address, + data: Encoding.to_hex(data), + gas: Encoding.to_hex(@gas) + } + + {:ok, receipt_hash} = Ethereumex.HttpClient.eth_send_transaction(tx) + wait_on_receipt_confirmed(receipt_hash) + :ok + end +end diff --git a/apps/itest/test/features/in_flight_exits.feature b/apps/itest/test/features/in_flight_exits.feature index 95295d9..9b8ee70 100644 --- a/apps/itest/test/features/in_flight_exits.feature +++ b/apps/itest/test/features/in_flight_exits.feature @@ -8,7 +8,7 @@ Feature: In Flight Exits And Bob gets in flight exit data for "5" ETH from his most recent deposit And Alice sends the most recently created transaction And Bob spends an output from the most recently sent transaction - And Alice starts an in flight exit from the most recently created transaction + And "Alice" starts an in flight exit from the most recently created transaction Then "Alice" verifies its in flight exit from the most recently created transaction Given Bob piggybacks inputs and outputs from Alices most recent in flight exit And Bob starts a piggybacked in flight exit using his most recently prepared in flight exit data @@ -35,7 +35,7 @@ Feature: In Flight Exits Given "Alice" deposits "10" ETH to the root chain Then "Alice" should have "10" ETH on the child chain after finality margin Given Alice creates a transaction for "5" ETH - And Alice starts an in flight exit from the most recently created transaction + And "Alice" starts an in flight exit from the most recently created transaction Then "Alice" verifies its in flight exit from the most recently created transaction Given Alice piggybacks output from her most recent in flight exit And "Alice" in flight transaction inputs are not spendable any more @@ -46,7 +46,7 @@ Feature: In Flight Exits Then "Alice" should have "10" ETH on the child chain after finality margin Given Alice creates a transaction for "5" ETH And Alice sends the most recently created transaction - And Alice starts an in flight exit from the most recently created transaction + And "Alice" starts an in flight exit from the most recently created transaction Then "Alice" verifies its in flight exit from the most recently created transaction Given Alice piggybacks output from her most recent in flight exit And "Alice" in flight transaction most recently piggybacked output is not spendable any more @@ -56,9 +56,19 @@ Feature: In Flight Exits Given "Alice" deposits "10" ETH to the root chain Then "Alice" should have "10" ETH on the child chain after finality margin Given Alice creates a transaction for "5" ETH - And Alice starts an in flight exit from the most recently created transaction + And "Alice" starts an in flight exit from the most recently created transaction Then "Alice" verifies its in flight exit from the most recently created transaction Given "Alice" is aware of available piggyback Then "Alice" in flight transaction inputs are not exitable any more Given Alice piggybacks output from her most recent in flight exit Then "Alice" can processes its own most recent in flight exit + + Scenario: In-flight exit can be deleted + Given "Alice" deposits "10" ETH to the root chain + Then "Alice" should have "10" ETH on the child chain after finality margin + Given Alice creates a transaction for "5" ETH + And "Alice" starts an in flight exit from the most recently created transaction + Then "Alice" verifies its in flight exit from the most recently created transaction + Given "Alice" is aware of available piggyback + When "Alice" deletes its most recent in flight exit + Then watcher does not report any byzantine events diff --git a/apps/itest/test/itest/in_flight_exits_test.exs b/apps/itest/test/itest/in_flight_exits_test.exs index fc97899..04592f7 100644 --- a/apps/itest/test/itest/in_flight_exits_test.exs +++ b/apps/itest/test/itest/in_flight_exits_test.exs @@ -29,6 +29,7 @@ defmodule InFlightExitsTests do alias Itest.ApiModel.WatcherSecurityCriticalConfiguration alias Itest.Client alias Itest.Fee + alias Itest.InFlightExitClient alias Itest.StandardExitChallengeClient alias Itest.StandardExitClient alias Itest.Transactions.Currency @@ -450,10 +451,12 @@ defmodule InFlightExitsTests do {:ok, Map.put(state, entity, bob_state)} end - defand ~r/^Alice starts an in flight exit from the most recently created transaction$/, _, state do + defand ~r/^"(?[^"]+)" starts an in flight exit from the most recently created transaction$/, + %{entity: entity}, + state do exit_game_contract_address = state["exit_game_contract_address"] in_flight_exit_bond_size = state["in_flight_exit_bond_size"] - %{address: address, txbytes: txbytes} = alice_state = state["Alice"] + %{address: address, txbytes: txbytes} = alice_state = state[entity] payload = %InFlightExitTxBytesBodySchema{txbytes: Encoding.to_hex(txbytes)} response = pull_api_until_successful(InFlightExit, :in_flight_exit_get_data, Watcher.new(), payload) exit_data = IfeExitData.to_struct(response) @@ -464,7 +467,6 @@ defmodule InFlightExitsTests do |> Map.put(:exit_data, exit_data) |> Map.put(:receipt_hashes, [receipt_hash | alice_state.receipt_hashes]) - entity = "Alice" {:ok, Map.put(state, entity, alice_state)} end @@ -958,6 +960,25 @@ defmodule InFlightExitsTests do assert Itest.Poller.exitable_utxo_absent?(address, input_pos) end + defwhen ~r/^"(?[^"]+)" deletes its most recent in flight exit$/, + %{entity: entity}, + state do + exit_game_contract_address = state["exit_game_contract_address"] + %{address: address, exit_data: exit_data} = state[entity] + + in_flight_exit_id = get_in_flight_exit_id(exit_game_contract_address, exit_data) + + _ = wait_for_min_exit_period() + InFlightExitClient.delete_in_flight_exit(address, exit_game_contract_address, in_flight_exit_id) + + {:ok, state} + end + + defthen ~r/^watcher does not report any byzantine events/, _, state do + assert all_events_in_status?([]) + {:ok, state} + end + ############################################################################################### #### #### PRIVATE