Skip to content

Commit

Permalink
Merge pull request #1077 from saratomaz/test_tx_with_invalid_datum
Browse files Browse the repository at this point in the history
Test tx with invalid datum
  • Loading branch information
mkoura committed May 13, 2022
2 parents 1b74ba3 + 21da99e commit 19c0508
Show file tree
Hide file tree
Showing 2 changed files with 322 additions and 136 deletions.
229 changes: 158 additions & 71 deletions cardano_node_tests/tests/test_plutus_spend_build.py
Expand Up @@ -1426,77 +1426,6 @@ def test_same_collateral_txin(
expected_fee_fund = 168_845
assert helpers.is_in_interval(tx_output_fund.fee, expected_fee_fund, frac=0.15)

@allure.link(helpers.get_vcs_link())
@pytest.mark.testnets
def test_no_datum_txout(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
):
"""Test using UTxO without datum hash in place of locked UTxO.
Expect failure.
Uses `cardano-cli transaction build` command for building the transactions.
* create a Tx output without a datum hash
* try to spend the UTxO like it was locked Plutus UTxO
* check that the expected error was raised
* (optional) check transactions in db-sync
"""
temp_template = common.get_test_id(cluster)
amount = 2_000_000

payment_addr = payment_addrs[0]
dst_addr = payment_addrs[1]

plutus_op = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
datum_file=plutus_common.DATUM_42_TYPED,
redeemer_file=plutus_common.REDEEMER_42_TYPED,
execution_cost=plutus_common.ALWAYS_SUCCEEDS_COST,
)
assert plutus_op.execution_cost # for mypy

redeem_cost = plutus_common.compute_cost(
execution_cost=plutus_op.execution_cost, protocol_params=cluster.get_protocol_params()
)

txouts = [
clusterlib.TxOut(address=payment_addr.address, amount=amount + redeem_cost.fee),
clusterlib.TxOut(address=payment_addr.address, amount=redeem_cost.collateral),
]
tx_files = clusterlib.TxFiles(signing_key_files=[payment_addr.skey_file])

tx_output_fund = cluster.send_tx(
src_address=payment_addr.address,
tx_name=temp_template,
txouts=txouts,
tx_files=tx_files,
join_txouts=False,
)

txid = cluster.get_txid(tx_body_file=tx_output_fund.out_file)
script_utxos = cluster.get_utxo(txin=f"{txid}#0")
collateral_utxos = cluster.get_utxo(txin=f"{txid}#1")

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addr,
dst_addr=dst_addr,
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=amount,
)
assert "not a Plutus script witnessed tx input" in str(excinfo.value)

# check expected fees
expected_fee_fund = 199_087
assert helpers.is_in_interval(tx_output_fund.fee, expected_fee_fund, frac=0.15)

@allure.link(helpers.get_vcs_link())
@pytest.mark.dbsync
@pytest.mark.testnets
Expand Down Expand Up @@ -2262,3 +2191,161 @@ def test_json_schema_untyped_invalid_type(
assert 'Expected a single field named "int", "bytes", "string", "list" or "map".' in str(
excinfo.value
)


@pytest.mark.testnets
class TestNegativeDatum:
"""Tests for Tx output locking using Plutus smart contracts with wrong datum."""

@allure.link(helpers.get_vcs_link())
def test_no_datum_txout(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
):
"""Test using UTxO without datum hash in place of locked UTxO.
Expect failure.
* create a Tx output without a datum hash
* try to spend the UTxO like it was locked Plutus UTxO
* check that the expected error was raised
"""
temp_template = common.get_test_id(cluster)
amount = 2_000_000

payment_addr = payment_addrs[0]
dst_addr = payment_addrs[1]

plutus_op = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
datum_file=plutus_common.DATUM_42_TYPED,
redeemer_file=plutus_common.REDEEMER_42_TYPED,
execution_cost=plutus_common.ALWAYS_SUCCEEDS_COST,
)
assert plutus_op.execution_cost # for mypy

redeem_cost = plutus_common.compute_cost(
execution_cost=plutus_op.execution_cost, protocol_params=cluster.get_protocol_params()
)

txouts = [
clusterlib.TxOut(address=payment_addr.address, amount=amount + redeem_cost.fee),
clusterlib.TxOut(address=payment_addr.address, amount=redeem_cost.collateral),
]
tx_files = clusterlib.TxFiles(signing_key_files=[payment_addr.skey_file])

tx_output_fund = cluster.send_tx(
src_address=payment_addr.address,
tx_name=temp_template,
txouts=txouts,
tx_files=tx_files,
join_txouts=False,
)

txid = cluster.get_txid(tx_body_file=tx_output_fund.out_file)
script_utxos = cluster.get_utxo(txin=f"{txid}#0")
collateral_utxos = cluster.get_utxo(txin=f"{txid}#1")

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_spend_locked_txin(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addr,
dst_addr=dst_addr,
script_utxos=script_utxos,
collateral_utxos=collateral_utxos,
plutus_op=plutus_op,
amount=amount,
)
assert "not a Plutus script witnessed tx input" in str(excinfo.value)

# check expected fees
expected_fee_fund = 199_087
assert helpers.is_in_interval(tx_output_fund.fee, expected_fee_fund, frac=0.15)

@allure.link(helpers.get_vcs_link())
@hypothesis.given(datum_value=st.text())
@common.hypothesis_settings()
def test_lock_tx_invalid_datum(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
datum_value: str,
):
"""Test locking a Tx output with an invalid datum.
Expect failure.
"""
temp_template = common.get_test_id(cluster)

datum_file = f"{temp_template}.datum"
with open(datum_file, "w", encoding="utf-8") as outfile:
json.dump(f'{{"{datum_value}"}}', outfile)

plutus_op = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
datum_file=Path(datum_file),
redeemer_cbor_file=plutus_common.REDEEMER_42_CBOR,
execution_cost=plutus_common.ALWAYS_SUCCEEDS_COST,
)

with pytest.raises(clusterlib.CLIError) as excinfo:
_build_fund_script(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=payment_addrs[0],
dst_addr=payment_addrs[1],
plutus_op=plutus_op,
)
assert "JSON object expected. Unexpected value" in str(excinfo.value)

@allure.link(helpers.get_vcs_link())
def test_unlock_tx_wrong_datum(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
):
"""Test locking a Tx output and try to spend it with a wrong datum.
Expect failure.
"""
temp_template = common.get_test_id(cluster)

plutus_op_1 = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
datum_file=plutus_common.DATUM_42_TYPED,
redeemer_cbor_file=plutus_common.REDEEMER_42_CBOR,
execution_cost=plutus_common.ALWAYS_SUCCEEDS_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_1,
)

# use a wrong datum to try to unlock the funds
plutus_op_2 = plutus_common.PlutusOp(
script_file=plutus_common.ALWAYS_SUCCEEDS_PLUTUS,
datum_file=plutus_common.DATUM_42,
redeemer_cbor_file=plutus_common.REDEEMER_42_CBOR,
execution_cost=plutus_common.ALWAYS_SUCCEEDS_COST,
)

with pytest.raises(clusterlib.CLIError) as excinfo:
_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_2,
amount=2_000_000,
)
assert "The Plutus script witness has the wrong datum (according to the UTxO)." in str(
excinfo.value
)

0 comments on commit 19c0508

Please sign in to comment.