Skip to content

Commit

Permalink
check reference inputs txins on dbsync
Browse files Browse the repository at this point in the history
  • Loading branch information
saratomaz committed Dec 6, 2022
1 parent 52da608 commit c0a9dfb
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 56 deletions.
164 changes: 109 additions & 55 deletions cardano_node_tests/tests/test_scripts.py
Expand Up @@ -9,11 +9,14 @@
import logging
import random
from pathlib import Path
from typing import Any
from typing import Dict
from typing import List
from typing import Optional

import allure
import pytest
from _pytest.fixtures import FixtureRequest
from cardano_clusterlib import clusterlib

from cardano_node_tests.cluster_management import cluster_management
Expand Down Expand Up @@ -1914,69 +1917,115 @@ def payment_addrs(

return addrs

@allure.link(helpers.get_vcs_link())
@common.PARAM_USE_BUILD_CMD
@pytest.mark.parametrize("script_version", ("simple_v1", "simple_v2"))
@pytest.mark.dbsync
def test_script_reference_utxo(
@pytest.fixture
def create_reference_script(
self,
cluster_manager: cluster_management.ClusterManager,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
use_build_cmd: bool,
script_version: str,
):
"""Send funds from script address where script is on reference UTxO."""
temp_template = f"{common.get_test_id(cluster)}_{script_version}_{use_build_cmd}"
src_addr = payment_addrs[0]
dst_addr = payment_addrs[1]
) -> Dict[str, Any]:
with cluster_manager.cache_fixture() as fixture_cache:
if fixture_cache.value:
return fixture_cache.value # type: ignore

fund_amount = 4_500_000
amount = 2_000_000
temp_template = common.get_test_id(cluster)

# create multisig script
if script_version == "simple_v1":
invalid_before = None
invalid_hereafter = None
src_addr = payment_addrs[0]
dst_addr = payment_addrs[1]

reference_type = clusterlib.ScriptTypes.SIMPLE_V1
script_type_str = "SimpleScriptV1"
# create multisig script v1

multisig_script = Path(f"{temp_template}_multisig.script")
script_content = {
multisig_script_v1 = Path(f"{temp_template}_multisig_v1.script")
script_content_v1 = {
"keyHash": cluster.g_address.get_payment_vkey_hash(dst_addr.vkey_file),
"type": "sig",
}
with open(multisig_script, "w", encoding="utf-8") as fp_out:
json.dump(script_content, fp_out, indent=4)
else:
invalid_before = 100
invalid_hereafter = cluster.g_query.get_slot_no() + 1_000
with open(multisig_script_v1, "w", encoding="utf-8") as fp_out:
json.dump(script_content_v1, fp_out, indent=4)

reference_utxo_v1, tx_out_reference_v1 = clusterlib_utils.create_reference_utxo(
temp_template=f"{temp_template}_v1",
cluster_obj=cluster,
payment_addr=src_addr,
dst_addr=dst_addr,
script_file=multisig_script_v1,
amount=4_000_000,
)
assert reference_utxo_v1.reference_script

reference_type = clusterlib.ScriptTypes.SIMPLE_V2
script_type_str = "SimpleScriptV2"
# create multisig script v2

multisig_script = cluster.g_transaction.build_multisig_script(
script_name=temp_template,
multisig_script_v2 = cluster.g_transaction.build_multisig_script(
script_name=f"{temp_template}_v2",
script_type_arg=clusterlib.MultiSigTypeArgs.ANY,
payment_vkey_files=[p.vkey_file for p in payment_addrs],
slot=invalid_before,
slot=cluster.g_query.get_slot_no() + 1_000,
slot_type_arg=clusterlib.MultiSlotTypeArgs.AFTER,
)

# create reference UTxO
reference_utxo, tx_out_reference = clusterlib_utils.create_reference_utxo(
temp_template=temp_template,
cluster_obj=cluster,
payment_addr=src_addr,
dst_addr=dst_addr,
script_file=multisig_script,
amount=4_000_000,
)
assert reference_utxo.reference_script
reference_utxo_v2, tx_out_reference_v2 = clusterlib_utils.create_reference_utxo(
temp_template=f"{temp_template}_v2",
cluster_obj=cluster,
payment_addr=src_addr,
dst_addr=dst_addr,
script_file=multisig_script_v2,
amount=4_000_000,
)
assert reference_utxo_v2.reference_script

scripts_data = {
"simple_v1": {
"invalid_before": None,
"invalid_hereafter": None,
"reference_type": clusterlib.ScriptTypes.SIMPLE_V1,
"script_type_str": "SimpleScriptV1",
"multisig_script": multisig_script_v1,
"reference_utxo": reference_utxo_v1,
"tx_out_reference": tx_out_reference_v1,
},
"simple_v2": {
"invalid_before": 100,
"invalid_hereafter": cluster.g_query.get_slot_no() + 1_000,
"reference_type": clusterlib.ScriptTypes.SIMPLE_V2,
"script_type_str": "SimpleScriptV2",
"multisig_script": multisig_script_v2,
"reference_utxo": reference_utxo_v2,
"tx_out_reference": tx_out_reference_v2,
},
}

fixture_cache.value = scripts_data

return scripts_data

@allure.link(helpers.get_vcs_link())
@common.PARAM_USE_BUILD_CMD
@pytest.mark.parametrize("script_version", ("simple_v1", "simple_v2"))
@pytest.mark.dbsync
def test_script_reference_utxo(
self,
cluster: clusterlib.ClusterLib,
payment_addrs: List[clusterlib.AddressRecord],
create_reference_script: Dict[str, Any],
script_version: str,
use_build_cmd: bool,
request: FixtureRequest,
):
"""Send funds from script address where script is on reference UTxO."""
temp_template = f"{common.get_test_id(cluster)}_{request.node.callspec.id}"
src_addr = payment_addrs[0]
dst_addr = payment_addrs[1]

fund_amount = 4_500_000
amount = 2_000_000

# create reference UTxO with the script
scripts_data_by_version = create_reference_script
script_data = scripts_data_by_version[script_version]

# create script address
script_address = cluster.g_address.gen_payment_addr(
addr_name=temp_template, payment_script_file=multisig_script
addr_name=temp_template, payment_script_file=script_data["multisig_script"]
)

# send funds to script address
Expand All @@ -1999,8 +2048,8 @@ def test_script_reference_utxo(
script_txins = [
clusterlib.ScriptTxIn(
txins=[],
reference_txin=reference_utxo,
reference_type=reference_type,
reference_txin=script_data["reference_utxo"],
reference_type=script_data["reference_type"],
)
]

Expand All @@ -2012,8 +2061,8 @@ def test_script_reference_utxo(
script_txins=script_txins,
fee_buffer=2_000_000,
tx_files=tx_files,
invalid_hereafter=invalid_hereafter,
invalid_before=invalid_before,
invalid_hereafter=script_data["invalid_hereafter"],
invalid_before=script_data["invalid_before"],
witness_override=2,
)
tx_signed = cluster.g_transaction.sign_tx(
Expand All @@ -2029,8 +2078,8 @@ def test_script_reference_utxo(
txouts=destinations,
script_txins=script_txins,
tx_files=tx_files,
invalid_hereafter=invalid_hereafter,
invalid_before=invalid_before,
invalid_hereafter=script_data["invalid_hereafter"],
invalid_before=script_data["invalid_before"],
)

# check final balances
Expand All @@ -2044,20 +2093,25 @@ def test_script_reference_utxo(
), f"Incorrect balance for destination address `{dst_addr.address}`"

# check that reference UTxO was NOT spent
assert cluster.g_query.get_utxo(utxo=reference_utxo), "Reference input was spent"
assert cluster.g_query.get_utxo(
utxo=script_data["reference_utxo"]
), "Reference input was spent"

dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_out_reference)
dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=script_data["tx_out_reference"])
dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_out_to)
# TODO: check reference script in db-sync (the `tx_out_from`)
dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_out_from)

# check expected script type
# TODO: moved the check to the end of the test because of XFAIL
if (
script_type_str == "SimpleScriptV1"
and reference_utxo.reference_script["script"]["type"] == "SimpleScriptV2"
script_data["script_type_str"] == "SimpleScriptV1"
and script_data["reference_utxo"].reference_script["script"]["type"] == "SimpleScriptV2"
):
pytest.xfail("Reported 'SimpleScriptV2', see node issue #4261")
assert reference_utxo.reference_script["script"]["type"] == script_type_str
assert (
script_data["reference_utxo"].reference_script["script"]["type"]
== script_data["script_type_str"]
)

@allure.link(helpers.get_vcs_link())
@common.PARAM_USE_BUILD_CMD
Expand Down
4 changes: 3 additions & 1 deletion cardano_node_tests/utils/dbsync_queries.py
Expand Up @@ -62,6 +62,8 @@ class TxDBRow(NamedTuple):
tx_out_data_hash: Optional[memoryview]
tx_out_inline_datum_hash: Optional[memoryview]
tx_out_reference_script_hash: Optional[memoryview]
tx_out_reference_script_tx_id: Optional[int]
tx_out_reference_script_id: Optional[int]
metadata_count: int
reserve_count: int
treasury_count: int
Expand Down Expand Up @@ -284,7 +286,7 @@ def query_tx(txhash: str) -> Generator[TxDBRow, None, None]:
" tx.id, tx.hash, tx.block_id, tx.block_index, tx.out_sum, tx.fee, tx.deposit, tx.size,"
" tx.invalid_before, tx.invalid_hereafter,"
" tx_out.id, tx_out.tx_id, tx_out.index, tx_out.address, tx_out.address_has_script,"
" tx_out.value, tx_out.data_hash, datum.hash, script.hash,"
" tx_out.value, tx_out.data_hash, datum.hash, script.hash, script.tx_id, script.id,"
" (SELECT COUNT(id) FROM tx_metadata WHERE tx_id=tx.id) AS metadata_count,"
" (SELECT COUNT(id) FROM reserve WHERE tx_id=tx.id) AS reserve_count,"
" (SELECT COUNT(id) FROM treasury WHERE tx_id=tx.id) AS treasury_count,"
Expand Down
40 changes: 40 additions & 0 deletions cardano_node_tests/utils/dbsync_utils.py
@@ -1,8 +1,10 @@
"""Functionality for interacting with db-sync."""
import functools
import itertools
import json
import logging
import time
from pathlib import Path
from typing import Any
from typing import Dict
from typing import List
Expand All @@ -15,6 +17,7 @@
from cardano_node_tests.utils import clusterlib_utils
from cardano_node_tests.utils import configuration
from cardano_node_tests.utils import dbsync_queries
from cardano_node_tests.utils import helpers

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -143,6 +146,7 @@ class TxRecord(NamedTuple):
collateral_outputs: List[clusterlib.UTXOData]
reference_inputs: List[clusterlib.UTXOData]
scripts: List[ScriptRecord]
script_txins: List[ScriptRecord]
redeemers: List[RedeemerRecord]
metadata: List[MetadataRecord]
reserve: List[ADAStashRecord]
Expand Down Expand Up @@ -544,6 +548,18 @@ def get_tx_record(txhash: str) -> TxRecord: # noqa: C901
for r in dbsync_queries.query_plutus_scripts(txhash=txhash)
]

script_txins = []
if reference_inputs:
for reference_input in reference_inputs:
script_txins += [
ScriptRecord(
hash=r.hash.hex(),
type=str(r.type),
serialised_size=int(r.serialised_size) if r.serialised_size else 0,
)
for r in dbsync_queries.query_plutus_scripts(txhash=reference_input.utxo_hash)
]

redeemers = []
if txdata.last_row.redeemer_count:
redeemers = [
Expand Down Expand Up @@ -579,6 +595,7 @@ def get_tx_record(txhash: str) -> TxRecord: # noqa: C901
collateral_outputs=collateral_outputs,
reference_inputs=reference_inputs,
scripts=scripts,
script_txins=script_txins,
redeemers=redeemers,
metadata=metadata,
reserve=reserve,
Expand Down Expand Up @@ -956,6 +973,29 @@ def check_tx(
f"({tx_reference_script_hashes} != {db_reference_script_hashes})"
)

# check reference scripts txins
txins_script_hashes = []

for r in tx_raw_output.script_txins:
if r.reference_txin and r.reference_txin.reference_script:
script_file = Path(f"{helpers.get_timestamped_rand_str()}.script")
with open(script_file, "w", encoding="utf-8") as outfile:
json.dump(r.reference_txin.reference_script["script"], outfile)

txins_script_hashes.append(
cluster_obj.g_transaction.get_policyid(script_file=script_file)
)

db_txins_script_hashes = {r.hash for r in response.script_txins if r.hash}

# a script is added to `script` table only the first time it is seen, so the record
# can be empty for the current transaction
if db_txins_script_hashes:
assert set(txins_script_hashes) == db_txins_script_hashes, (
"Reference scripts txins don't match "
f"({set(txins_script_hashes)} != {db_txins_script_hashes})"
)

return response


Expand Down

0 comments on commit c0a9dfb

Please sign in to comment.