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

Add cleanup code plutus spend tests #1088

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 170 additions & 17 deletions cardano_node_tests/tests/test_plutus_spend_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import shutil
from pathlib import Path
from typing import Any
from typing import Generator
from typing import List
from typing import Optional
from typing import Tuple
Expand All @@ -13,6 +14,7 @@
import hypothesis
import hypothesis.strategies as st
import pytest
from _pytest.fixtures import FixtureRequest
from cardano_clusterlib import clusterlib

from cardano_node_tests.tests import common
Expand Down Expand Up @@ -461,9 +463,7 @@ def test_txout_locking(
@pytest.mark.dbsync
@pytest.mark.testnets
def test_context_equivalance(
self,
cluster: clusterlib.ClusterLib,
pool_users: List[clusterlib.PoolUser],
self, cluster: clusterlib.ClusterLib, pool_users: List[clusterlib.PoolUser]
):
"""Test context equivalence while spending a locked UTxO.

Expand Down Expand Up @@ -1077,6 +1077,7 @@ def test_partial_spending(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
):
"""Test spending part of funds (Lovelace and native tokens) on a locked UTxO.

Expand All @@ -1091,6 +1092,7 @@ def test_partial_spending(
* check expected Plutus cost
* (optional) check transactions in db-sync
"""
# pylint: disable=too-many-locals
temp_template = common.get_test_id(cluster)

token_rand = clusterlib.get_rand_str(5)
Expand Down Expand Up @@ -1157,6 +1159,7 @@ def test_partial_spending(
script_lovelace_balance = functools.reduce(
lambda x, y: x + y.amount, script_lovelace_utxos, 0
)

# Lovelace balance on change UTxOs
change_lovelace_utxos = [
u for u in [*change_utxos, *build_change_utxos] if u.coin == clusterlib.DEFAULT_COIN
Expand All @@ -1165,6 +1168,24 @@ def test_partial_spending(
lambda x, y: x + y.amount, change_lovelace_utxos, 0
)

# withdrawal script address
def _withdrawal_script_address():
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=change_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=2_000_000,
tokens=[plutus_common.Token(coin=t.token, amount=80) for t in tokens],
)

request.addfinalizer(_withdrawal_script_address)

cluster.get_utxo(script_utxos[0].address)

assert (
change_lovelace_balance == script_lovelace_balance - tx_output_spend.fee - amount_spend
)
Expand Down Expand Up @@ -1312,6 +1333,7 @@ def test_collateral_w_tokens(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
):
"""Test spending the locked UTxO while collateral contains native tokens.

Expand Down Expand Up @@ -1354,6 +1376,41 @@ def test_collateral_w_tokens(
tokens_collateral=tokens_rec,
)

# withdrawal script address
def _withdrawal_script_address():
redeem_cost = plutus_common.compute_cost(
execution_cost=plutus_op.execution_cost,
protocol_params=cluster.get_protocol_params(),
)

destinations = [
clusterlib.TxOut(address=payment_addrs[1].address, amount=redeem_cost.collateral)
]
tx_files = clusterlib.TxFiles(signing_key_files=[payment_addrs[0].skey_file])

tx_raw_output = cluster.send_funds(
src_address=payment_addrs[0].address,
destinations=destinations,
tx_name=temp_template,
tx_files=tx_files,
)

txid_collateral = cluster.get_txid(tx_body_file=tx_raw_output.out_file)
collateral_utxos_without_tokens = cluster.get_utxo(txin=f"{txid_collateral}#0")

_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos_without_tokens,
plutus_op=plutus_op,
amount=2_000_000,
)

request.addfinalizer(_withdrawal_script_address)

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_spend_locked_txin(
temp_template=temp_template,
Expand All @@ -1379,6 +1436,7 @@ def test_same_collateral_txin(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
):
"""Test spending the locked UTxO while using the same UTxO as collateral.

Expand All @@ -1401,14 +1459,29 @@ def test_same_collateral_txin(
execution_cost=plutus_common.ALWAYS_SUCCEEDS_COST,
)

script_utxos, __, tx_output_fund = _build_fund_script(
script_utxos, collateral_utxos, tx_output_fund = _build_fund_script(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
plutus_op=plutus_op,
)

# withdrawal script address
def _withdrawal_script_address():
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=2_000_000,
)

request.addfinalizer(_withdrawal_script_address)

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_spend_locked_txin(
temp_template=temp_template,
Expand All @@ -1420,6 +1493,7 @@ def test_same_collateral_txin(
plutus_op=plutus_op,
amount=2_000_000,
)

assert "Expected key witnessed collateral" in str(excinfo.value)

# check expected fees
Expand All @@ -1441,6 +1515,7 @@ def test_guessing_game(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
variant: str,
):
"""Test locking a Tx output with a Plutus script and spending the locked UTxO.
Expand All @@ -1458,6 +1533,37 @@ def test_guessing_game(
"""
temp_template = f"{common.get_test_id(cluster)}_{variant}"

plutus_op = plutus_common.PlutusOp(
script_file=plutus_common.GUESSING_GAME_PLUTUS,
datum_file=plutus_common.DATUM_42_TYPED,
redeemer_file=plutus_common.REDEEMER_42_TYPED,
execution_cost=plutus_common.GUESSING_GAME_COST,
)

script_utxos, collateral_utxos, __ = _build_fund_script(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
plutus_op=plutus_op,
)

# withdrawal script address
def _withdrawal_script_address():
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=2_000_000,
)

# add the finalizer just one time
request.addfinalizer(_withdrawal_script_address)

if variant == "42_43":
datum_file = plutus_common.DATUM_42_TYPED
redeemer_file = plutus_common.REDEEMER_43_TYPED
Expand All @@ -1470,21 +1576,13 @@ def test_guessing_game(
else:
raise AssertionError("Unknown test variant.")

plutus_op = plutus_common.PlutusOp(
plutus_op_variant = plutus_common.PlutusOp(
script_file=plutus_common.GUESSING_GAME_PLUTUS,
datum_file=datum_file,
redeemer_file=redeemer_file,
execution_cost=plutus_common.GUESSING_GAME_COST,
)

script_utxos, collateral_utxos, __ = _build_fund_script(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
plutus_op=plutus_op,
)

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_spend_locked_txin(
temp_template=temp_template,
Expand All @@ -1493,18 +1591,21 @@ def test_guessing_game(
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
plutus_op=plutus_op_variant,
amount=2_000_000,
)

assert "The Plutus script evaluation failed" in str(excinfo.value)
assert "The Plutus script evaluation failed" in str(
excinfo.value
) or "The Plutus script witness has the wrong datum" in str(excinfo.value)

@allure.link(helpers.get_vcs_link())
@pytest.mark.testnets
def test_two_scripts_spending_one_fail(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
):
"""Test locking two Tx outputs with two different Plutus scripts in single Tx, one fails.

Expand Down Expand Up @@ -1596,6 +1697,22 @@ def test_two_scripts_spending_one_fail(
collateral_utxos1 = cluster.get_utxo(txin=f"{txid_fund}#3")
collateral_utxos2 = cluster.get_utxo(txin=f"{txid_fund}#4")

# withdrawal script address
def _withdrawal_script_address():
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos1,
collateral_utxos=collateral_utxos1,
plutus_op=plutus_op1,
amount=2_000_000,
)

# add the finalizer
request.addfinalizer(_withdrawal_script_address)

# Step 2: spend the "locked" UTxOs

assert plutus_op1.datum_file and plutus_op2.datum_file
Expand Down Expand Up @@ -1650,7 +1767,7 @@ def fund_script_guessing_game(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
) -> Tuple[List[clusterlib.UTXOData], List[clusterlib.UTXOData]]:
) -> Generator[Tuple[List[clusterlib.UTXOData], List[clusterlib.UTXOData]], None, None]:
"""Fund a Plutus script and create the locked UTxO and collateral UTxO.

Uses `cardano-cli transaction build` command for building the transactions.
Expand All @@ -1671,7 +1788,26 @@ def fund_script_guessing_game(
plutus_op=plutus_op,
)

return script_utxos, collateral_utxos
yield script_utxos, collateral_utxos

# withdrawal script address
plutus_op = plutus_common.PlutusOp(
script_file=plutus_common.GUESSING_GAME_UNTYPED_PLUTUS,
datum_file=plutus_common.DATUM_42,
redeemer_value="42",
execution_cost=plutus_common.GUESSING_GAME_UNTYPED_COST,
)

_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=self.AMOUNT,
)

def _int_out_of_range(
self,
Expand Down Expand Up @@ -2305,6 +2441,7 @@ def test_unlock_tx_wrong_datum(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
request: FixtureRequest,
):
"""Test locking a Tx output and try to spend it with a wrong datum.

Expand All @@ -2327,6 +2464,22 @@ def test_unlock_tx_wrong_datum(
plutus_op=plutus_op_1,
)

# withdrawal script address
def _withdrawal_script_address():
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op_1,
amount=2_000_000,
)

# add the finalizer
request.addfinalizer(_withdrawal_script_address)

# use a wrong datum to try to unlock the funds
plutus_op_2 = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
Expand Down
Loading