Skip to content
Merged
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
6 changes: 1 addition & 5 deletions cardano_node_tests/tests/test_chain_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ def _repeat_submit(cluster_obj: clusterlib.ClusterLib, tx_file: pl.Path) -> str:
try:
cluster_obj.g_transaction.submit_tx_bare(tx_file=tx_file)
except clusterlib.CLIError as exc:
exc_str = str(exc)
inputs_spent = (
"All inputs are spent" in exc_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in exc_str
)
inputs_spent = helpers.is_inputs_spent_err(str(exc))
if r == 0 and inputs_spent:
err_str = "Tx input is missing, maybe temporary fork happened?"
elif inputs_spent:
Expand Down
13 changes: 4 additions & 9 deletions cardano_node_tests/tests/test_tx_many_utxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def many_utxos(
less_than_1_ada = int(float(multiple / 20) * 1_000_000)
amount = less_than_1_ada + 1_000_000

# Repeat transaction when "BadInputsUTxO" error happens
# Repeat transaction when the Tx inputs were already spent
excp: clusterlib.CLIError | None = None
for r in range(2):
if r > 0:
Expand All @@ -110,16 +110,11 @@ def many_utxos(
amount=amount,
)
except clusterlib.CLIError as err:
# The "BadInputsUTxO" error happens when a single UTxO is used in two
# transactions. This can happen from time to time, we stress
# The "inputs already spent" error happens when a single UTxO is used
# in two transactions. This can happen from time to time, we stress
# the network here and waiting for 2 blocks may not be enough to get a
# transaction through.
exc_str = str(err)
inputs_spent = (
"All inputs are spent" in exc_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in exc_str
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str(err)):
raise
excp = err
else:
Expand Down
6 changes: 1 addition & 5 deletions cardano_node_tests/tests/test_tx_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,7 @@ def test_query_mempool_txin(
try:
cluster.g_transaction.submit_tx_bare(tx_file=out_file_signed)
except clusterlib.CLIError as exc:
exc_str = str(exc)
inputs_spent = (
"All inputs are spent" in exc_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in exc_str
)
inputs_spent = helpers.is_inputs_spent_err(str(exc))
if r == 0 or not inputs_spent:
raise
break
Expand Down
17 changes: 5 additions & 12 deletions cardano_node_tests/tests/test_tx_negative.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,7 @@ def test_duplicated_tx(
exc_value = str(excinfo.value)
with common.allow_unstable_error_messages():
assert (
"All inputs are spent" in exc_value # In cardano-node >= 10.6.0
or "(ValueNotConservedUTxO" in exc_value
helpers.is_inputs_spent_err(exc_value) or "(ValueNotConservedUTxO" in exc_value
), exc_value

@allure.link(helpers.get_vcs_link())
Expand Down Expand Up @@ -1310,7 +1309,7 @@ def test_nonexistent_utxo_ix(
* Get valid UTxO from payment address
* Modify UTxO index to nonexistent value (5)
* Attempt to build or submit transaction using invalid UTxO index
* Check that transaction fails with empty UTxO or BadInputsUTxO error
* Check that transaction fails with empty UTxO or inputs already spent error
"""
temp_template = common.get_test_id(cluster)

Expand All @@ -1336,10 +1335,7 @@ def test_nonexistent_utxo_ix(
), err_str
elif build_method == clusterlib_utils.BuildMethods.BUILD_RAW:
with common.allow_unstable_error_messages():
assert (
"All inputs are spent" in err_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in err_str
), err_str
assert helpers.is_inputs_spent_err(err_str), err_str
else:
msg = f"Unsupported build method: {build_method}"
raise ValueError(msg)
Expand All @@ -1363,7 +1359,7 @@ def test_nonexistent_utxo_hash(
* Get valid UTxO from payment address
* Modify last 4 characters of UTxO hash to create nonexistent hash
* Attempt to build or submit transaction using invalid UTxO hash
* Check that transaction fails with empty UTxO or BadInputsUTxO error
* Check that transaction fails with empty UTxO or inputs already spent error
"""
temp_template = common.get_test_id(cluster)

Expand All @@ -1390,10 +1386,7 @@ def test_nonexistent_utxo_hash(
), err_str
elif build_method == clusterlib_utils.BuildMethods.BUILD_RAW:
with common.allow_unstable_error_messages():
assert (
"All inputs are spent" in err_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in err_str
), err_str
assert helpers.is_inputs_spent_err(err_str), err_str
else:
msg = f"Unsupported build method: {build_method}"
raise ValueError(msg)
Expand Down
7 changes: 2 additions & 5 deletions cardano_node_tests/tests/tests_plutus/spend_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from cardano_node_tests.tests import plutus_common
from cardano_node_tests.utils import clusterlib_utils
from cardano_node_tests.utils import dbsync_utils
from cardano_node_tests.utils import helpers
from cardano_node_tests.utils import tx_view
from cardano_node_tests.utils.versions import VERSIONS

Expand Down Expand Up @@ -302,11 +303,7 @@ def _build_spend_locked_txin( # noqa: C901
):
issues.ledger_4198.finish_test()
# Check if resubmitting failed because an input UTxO was already spent
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str_exc):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down
8 changes: 2 additions & 6 deletions cardano_node_tests/tests/tests_plutus/spend_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from cardano_node_tests.tests import plutus_common
from cardano_node_tests.utils import clusterlib_utils
from cardano_node_tests.utils import dbsync_utils
from cardano_node_tests.utils import helpers
from cardano_node_tests.utils import tx_view
from cardano_node_tests.utils.versions import VERSIONS

Expand Down Expand Up @@ -297,12 +298,7 @@ def _spend_locked_txin( # noqa: C901
cluster_obj.g_transaction.submit_tx_bare(tx_file=tx_signed)
except clusterlib.CLIError as exc:
# Check if resubmitting failed because an input UTxO was already spent
str_exc = str(exc)
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str(exc)):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,7 @@ def test_with_total_return_collateral(
):
issues.ledger_4198.finish_test()
# Check if resubmitting failed because an input UTxO was already spent
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str_exc):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down Expand Up @@ -361,11 +357,7 @@ def test_collateral_with_tokens(
):
issues.ledger_4198.finish_test()
# Check if resubmitting failed because an input UTxO was already spent
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str_exc):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@ def test_with_total_return_collateral(
):
issues.ledger_4198.finish_test()
# Check if resubmitting failed because an input UTxO was already spent
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str_exc):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down Expand Up @@ -336,11 +332,7 @@ def test_collateral_with_tokens(
):
issues.ledger_4198.finish_test()
# Check if resubmitting failed because an input UTxO was already spent
inputs_spent = (
"All inputs are spent" in str_exc # In cardano-node >= 10.6.0
or "BadInputsUTxO" in str_exc
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str_exc):
raise
else:
pytest.fail("Transaction was not submitted successfully")
Expand Down
20 changes: 20 additions & 0 deletions cardano_node_tests/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,26 @@ def is_in_interval(num1: float, num2: float, *, frac: float = 0.1) -> bool:
return _min <= num1 <= _max


def is_inputs_spent_err(err_str: str) -> bool:
"""Check if the error message indicates that the Tx inputs were already spent.

The ledger reports this condition with a different error in each era, so all the known
variants are accepted. In the Dijkstra era the Conway mempool failure is injected as the
dedicated `AllInputsAreSpent` failure.

Args:
err_str: An error message to check.

Returns:
bool: `True` if the error was caused by already spent Tx inputs.
"""
return (
"All inputs are spent" in err_str # Conway era, in cardano-node >= 10.6.0
or "AllInputsAreSpent" in err_str # Dijkstra era
or "BadInputsUTxO" in err_str
)


@functools.lru_cache(maxsize=100)
def tool_has(command: str) -> bool:
"""Check if a tool has a subcommand or argument available.
Expand Down
8 changes: 2 additions & 6 deletions cardano_node_tests/utils/submit_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from cardano_node_tests.utils import cluster_nodes
from cardano_node_tests.utils import custom_clusterlib
from cardano_node_tests.utils import helpers
from cardano_node_tests.utils import http_client

LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -150,12 +151,7 @@ def submit_tx(
err = None
except SubmitApiError as exc:
# Check if resubmitting failed because an input UTxO was already spent
exc_str = str(exc)
inputs_spent = (
"All inputs are spent" in exc_str # In cardano-node >= 10.6.0
or "BadInputsUTxO" in exc_str
)
if not inputs_spent:
if not helpers.is_inputs_spent_err(str(exc)):
raise
err = exc
# If here, the TX is likely still in mempool and we need to wait
Expand Down
28 changes: 28 additions & 0 deletions framework_tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,34 @@ def test_custom_frac(self):
assert helpers.is_in_interval(79, 100, frac=0.2) is False


class TestIsInputsSpentErr:
"""Tests for `is_inputs_spent_err`."""

@pytest.mark.parametrize(
"err_str",
(
'ConwayApplyTxError (ConwayMempoolFailure "All inputs are spent." :| [])',
"DijkstraApplyTxError (AllInputsAreSpent :| [])",
"ShelleyTxValidationError (UtxowFailure (UtxoFailure (BadInputsUTxO ...",
),
)
def test_known_variants(self, err_str: str):
"""Recognize the error variant of each era."""
assert helpers.is_inputs_spent_err(err_str) is True

@pytest.mark.parametrize(
"err_str",
(
"",
'ConwayApplyTxError (ConwayMempoolFailure "Insufficient collateral" :| [])',
"ValueNotConservedUTxO",
),
)
def test_unrelated_errors(self, err_str: str):
"""Don't match errors with an unrelated cause."""
assert helpers.is_inputs_spent_err(err_str) is False


class TestToolHas:
"""Tests for `tool_has`.

Expand Down
Loading