Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: payment v2 with standard exit #1589

Merged
2 changes: 0 additions & 2 deletions apps/omg_watcher/lib/omg_watcher/exit_processor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ defmodule OMG.Watcher.ExitProcessor do
use OMG.Utils.LoggerExt
require Utxo

@timeout 60_000

### Client

@doc """
Expand Down
31 changes: 11 additions & 20 deletions priv/cabbage/apps/itest/lib/standard_exit_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,29 @@ defmodule Itest.StandardExitClient do
@sleep_retry_sec 5_000
@retry_count 120

def start_standard_exit(%__MODULE__{utxo: %Utxo{utxo_pos: utxo_pos}} = se) do
@default_tx_type ExPlasma.payment_v1()

def start_standard_exit(_, tx_type \\ @default_tx_type)

def start_standard_exit(%__MODULE__{utxo: %Utxo{utxo_pos: utxo_pos}} = se, tx_type) do
_ = Logger.info("Starting standard exit for UTXO at #{utxo_pos}")

se
|> get_exit_data()
|> get_currency()
|> get_exit_game_contract_address()
|> get_exit_game_contract_address(tx_type)
|> add_exit_queue()
|> get_bond_size_for_standard_exit()
|> do_start_standard_exit()
|> get_standard_exit_id()
end

def start_standard_exit(address) do
def start_standard_exit(address, tx_type) do
_ = Logger.info("Starting standard exit for #{address}")

%__MODULE__{address: address}
|> get_utxo()
|> start_standard_exit()
|> start_standard_exit(tx_type)
end

def complete_standard_exit(address) do
Expand All @@ -89,7 +93,7 @@ defmodule Itest.StandardExitClient do
_ = Logger.info("Waiting and processing a standard exit by #{se.address}")

se
|> get_exit_game_contract_address()
|> get_exit_game_contract_address(@default_tx_type)
|> wait_for_exit_period()
|> process_exit(Keyword.get(opts, :n_exits, 1))
|> calculate_total_gas_used()
Expand Down Expand Up @@ -123,8 +127,8 @@ defmodule Itest.StandardExitClient do
%{se | currency: Encoding.to_binary(se.utxo.currency)}
end

defp get_exit_game_contract_address(se) do
exit_game_contract_address = Itest.PlasmaFramework.exit_game_contract_address(ExPlasma.payment_v1())
defp get_exit_game_contract_address(se, tx_type) do
exit_game_contract_address = Itest.PlasmaFramework.exit_game_contract_address(tx_type)
%{se | exit_game_contract_address: exit_game_contract_address}
end

Expand Down Expand Up @@ -230,19 +234,6 @@ defmodule Itest.StandardExitClient do
|> ABI.TypeDecoder.decode([{:uint, 160}])
|> hd()

data = ABI.encode("getNextExit(uint256,address)", [Itest.PlasmaFramework.vault_id(se.currency), se.currency])

{:ok, result} = Ethereumex.HttpClient.eth_call(%{to: Itest.PlasmaFramework.address(), data: Encoding.to_hex(data)})

next_exit_id =
result
|> Encoding.to_binary()
|> ABI.TypeDecoder.decode([{:uint, 256}])
|> hd()

# double check correctness, our exit ID must be the first one in the priority queue
^standard_exit_id = next_exit_id &&& (1 <<< 160) - 1

%{se | standard_exit_id: standard_exit_id}
end

Expand Down
14 changes: 14 additions & 0 deletions priv/cabbage/apps/itest/test/features/payment_v2.feature
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
Feature: Payment V2 transaction

Scenario: Alice sends Bob ETH with payment v1 and v2
Given Alice has an ethereum account
Given Bob has an ethereum account
When Alice deposits "4" ETH to the root chain
Then Alice should have "4" ETH on the child chain
When Alice sends Bob "1" ETH on the child chain with payment v1
Then Bob should have "1" ETH on the child chain
When Alice sends Bob "2" ETH on the child chain with payment v2
Then Bob should have "3" ETH on the child chain

Scenario: payment V2 output can exit and is recognized
Given Alice has an ethereum account
Given Bob has an ethereum account
When Alice deposits "4" ETH to the root chain
Then Alice should have "4" ETH on the child chain
When Alice sends Bob "2" ETH on the child chain with payment v2
Then Bob should have "2" ETH on the child chain
When Bob starts a standard exit with the payment v2 output
Then Bob should no longer see the exiting utxo on the child chain
When Somebody processes the standard exit on the child chain
Then Bob should have "0" ETH on the child chain
85 changes: 49 additions & 36 deletions priv/cabbage/apps/itest/test/itest/payment_v2_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,83 +18,96 @@ defmodule PaymentV2Test do
alias Itest.Account

alias Itest.Client
alias Itest.StandardExitClient
alias Itest.Transactions.Currency

@payment_v2_tx_type 2

setup do
[alice, bob] =
Enum.map(
Account.take_accounts(2),
fn {account, pkey} -> %{account: account, pkey: pkey} end
)

%{alice: alice, bob: bob}
defgiven ~r/^(?<user>[\w]+) has an ethereum account$/, %{user: user}, state do
[{account, pkey}] = Account.take_accounts(1)
{:ok, Map.put(state, user, %{account: account, pkey: pkey})}
end

defwhen ~r/^Alice deposits "(?<amount>[^"]+)" ETH to the root chain$/,
%{amount: amount},
%{alice: alice} = state do
defwhen ~r/^(?<user>[\w]+) deposits "(?<amount>[^"]+)" ETH to the root chain$/,
%{user: user, amount: amount},
state do
user = state[user]

{:ok, _receipt_hash} =
amount
|> Currency.to_wei()
|> Client.deposit(alice.account, Itest.PlasmaFramework.vault(Currency.ether()))
|> Client.deposit(user.account, Itest.PlasmaFramework.vault(Currency.ether()))

{:ok, state}
end

defthen ~r/^Alice should have "(?<amount>[^"]+)" ETH on the child chain$/,
%{amount: amount},
%{alice: alice} = state do
defthen ~r/^(?<user>[\w]+) should have "(?<amount>[^"]+)" ETH on the child chain$/,
%{user: user, amount: amount},
state do
user = state[user]
expecting_amount = Currency.to_wei(amount)
balance = Client.get_exact_balance(alice.account, expecting_amount)
balance = balance["amount"]
balance = Client.get_exact_balance(user.account, expecting_amount)["amount"] || 0

assert_equal(expecting_amount, balance, "For #{alice.account}")
assert_equal(expecting_amount, balance, "For #{user.account}")

{:ok, state}
end

defwhen ~r/^Alice sends Bob "(?<amount>[^"]+)" ETH on the child chain with payment v1$/,
%{amount: amount},
%{alice: alice, bob: bob} = state do
defwhen ~r/^(?<sender>[\w]+) sends (?<receiver>[\w]+) "(?<amount>[^"]+)" ETH on the child chain with payment v1$/,
%{sender: sender, receiver: receiver, amount: amount},
state do
sender = state[sender]
receiver = state[receiver]

{:ok, [sign_hash, typed_data, _txbytes]} =
Client.create_transaction(
Currency.to_wei(amount),
alice.account,
bob.account
sender.account,
receiver.account
)

_ = Client.submit_transaction(typed_data, sign_hash, [alice.pkey])
_ = Client.submit_transaction(typed_data, sign_hash, [sender.pkey])

{:ok, state}
end

defwhen ~r/^Alice sends Bob "(?<amount>[^"]+)" ETH on the child chain with payment v2$/,
%{amount: amount},
%{alice: alice, bob: bob} = state do
defwhen ~r/^(?<sender>[\w]+) sends (?<receiver>[\w]+) "(?<amount>[^"]+)" ETH on the child chain with payment v2$/,
%{sender: sender, receiver: receiver, amount: amount},
state do
sender = state[sender]
receiver = state[receiver]

{:ok, [sign_hash, typed_data, _txbytes]} =
Client.create_transaction(
Currency.to_wei(amount),
alice.account,
bob.account,
sender.account,
receiver.account,
Currency.ether(),
@payment_v2_tx_type
)

_ = Client.submit_transaction(typed_data, sign_hash, [alice.pkey])
_ = Client.submit_transaction(typed_data, sign_hash, [sender.pkey])

{:ok, state}
end

defthen ~r/^Bob should have "(?<amount>[^"]+)" ETH on the child chain$/,
%{amount: amount},
%{bob: bob} = state do
expecting_amount = Currency.to_wei(amount)
balance = Client.get_exact_balance(bob.account, expecting_amount)["amount"]
defwhen ~r/^(?<user>[\w]+) starts a standard exit with the payment v2 output$/, %{user: user}, state do
user = state[user]
se = StandardExitClient.start_standard_exit(user.account, @payment_v2_tx_type)
state = Map.put_new(state, :standard_exit, se)

assert_equal(expecting_amount, balance, "For Bob: #{bob.account}")
{:ok, state}
end

defthen ~r/^(?<user>[\w]+) should no longer see the exiting utxo on the child chain$/, %{user: user}, state do
user = state[user]
assert Itest.Poller.utxo_absent?(user.account, state.standard_exit.utxo.utxo_pos)
assert Itest.Poller.exitable_utxo_absent?(user.account, state.standard_exit.utxo.utxo_pos)
{:ok, state}
end

defwhen ~r/^Somebody processes the standard exit on the child chain$/, _, state do
StandardExitClient.wait_and_process_standard_exit(state.standard_exit)
{:ok, state}
end

Expand Down