Skip to content

Commit 93f9362

Browse files
tacmotacffls
andauthored
generalize plutus scripts (#396)
* generalize plutus scripts Refactor plutus scripts to reduce amount of works of adding new plutus versions. * Upload without token if created from a fork * further improvements --------- Co-authored-by: Jerry <[email protected]>
1 parent 075ab91 commit 93f9362

File tree

7 files changed

+107
-132
lines changed

7 files changed

+107
-132
lines changed

.github/workflows/main.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ jobs:
3535
if: ${{ matrix.python-version == '3.11' }}
3636
uses: codecov/codecov-action@v4
3737
with:
38-
fail_ci_if_error: true
39-
token: ${{ secrets.CODECOV_TOKEN }}
38+
fail_ci_if_error: false
39+
token: ${{ secrets.CODECOV_TOKEN || '' }}
4040
- name: Run static analyses
4141
if: ${{ matrix.python-version == '3.11' }}
4242
run: |
@@ -72,8 +72,8 @@ jobs:
7272
if: ${{ matrix.python-version == '3.11' }}
7373
uses: codecov/codecov-action@v4
7474
with:
75-
fail_ci_if_error: true
76-
token: ${{ secrets.CODECOV_TOKEN }}
75+
fail_ci_if_error: false
76+
token: ${{ secrets.CODECOV_TOKEN || '' }}
7777

7878
- name: Dump docker logs
7979
if: failure()

pycardano/backend/blockfrost.py

+7-27
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,7 @@
2020
from pycardano.hash import SCRIPT_HASH_SIZE, DatumHash, ScriptHash
2121
from pycardano.nativescript import NativeScript
2222
from pycardano.network import Network
23-
from pycardano.plutus import (
24-
ExecutionUnits,
25-
PlutusV1Script,
26-
PlutusV2Script,
27-
PlutusV3Script,
28-
script_hash,
29-
)
23+
from pycardano.plutus import ExecutionUnits, PlutusScript, ScriptType, script_hash
3024
from pycardano.serialization import RawCBOR
3125
from pycardano.transaction import (
3226
Asset,
@@ -42,9 +36,7 @@
4236
__all__ = ["BlockFrostChainContext"]
4337

4438

45-
def _try_fix_script(
46-
scripth: str, script: Union[PlutusV1Script, PlutusV2Script, PlutusV3Script]
47-
) -> Union[PlutusV1Script, PlutusV2Script, PlutusV3Script]:
39+
def _try_fix_script(scripth: str, script: PlutusScript) -> PlutusScript:
4840
if str(script_hash(script)) == scripth:
4941
return script
5042
else:
@@ -180,25 +172,13 @@ def protocol_param(self) -> ProtocolParameters:
180172
)
181173
return self._protocol_param
182174

183-
def _get_script(
184-
self, script_hash: str
185-
) -> Union[PlutusV1Script, PlutusV2Script, PlutusV3Script, NativeScript]:
175+
def _get_script(self, script_hash: str) -> ScriptType:
186176
script_type = self.api.script(script_hash).type
187-
if script_type == "plutusV1":
188-
v1script = PlutusV1Script(
189-
bytes.fromhex(self.api.script_cbor(script_hash).cbor)
190-
)
191-
return _try_fix_script(script_hash, v1script)
192-
elif script_type == "plutusV2":
193-
v2script = PlutusV2Script(
194-
bytes.fromhex(self.api.script_cbor(script_hash).cbor)
195-
)
196-
return _try_fix_script(script_hash, v2script)
197-
elif script_type == "plutusV3":
198-
v3script = PlutusV3Script(
199-
bytes.fromhex(self.api.script_cbor(script_hash).cbor)
177+
if script_type.startsWith("plutusV"):
178+
ps = PlutusScript.from_version(
179+
script_type[-1], bytes.fromhex(self.api.script_cbor(script_hash).cbor)
200180
)
201-
return _try_fix_script(script_hash, v3script)
181+
return _try_fix_script(script_hash, ps)
202182
else:
203183
script_json: JsonDict = self.api.script_json(
204184
script_hash, return_type="json"

pycardano/backend/kupo.py

+6-14
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@
88
from pycardano.backend.blockfrost import _try_fix_script
99
from pycardano.hash import DatumHash, ScriptHash
1010
from pycardano.network import Network
11-
from pycardano.plutus import (
12-
ExecutionUnits,
13-
PlutusV1Script,
14-
PlutusV2Script,
15-
PlutusV3Script,
16-
)
11+
from pycardano.plutus import ExecutionUnits, PlutusScript
1712
from pycardano.serialization import RawCBOR
1813
from pycardano.transaction import (
1914
Asset,
@@ -177,14 +172,11 @@ def _utxos_kupo(self, address: str) -> List[UTxO]:
177172
if script_hash:
178173
kupo_script_url = self._kupo_url + "/scripts/" + script_hash
179174
script = requests.get(kupo_script_url).json()
180-
if script["language"] == "plutus:v3":
181-
script = PlutusV3Script(bytes.fromhex(script["script"]))
182-
script = _try_fix_script(script_hash, script)
183-
elif script["language"] == "plutus:v2":
184-
script = PlutusV2Script(bytes.fromhex(script["script"]))
185-
script = _try_fix_script(script_hash, script)
186-
elif script["language"] == "plutus:v1":
187-
script = PlutusV1Script(bytes.fromhex(script["script"]))
175+
ver = int(script["language"].removeprefix("plutus:v"))
176+
if 1 <= ver <= 3:
177+
script = PlutusScript.from_version(
178+
ver, bytes.fromhex(script["script"])
179+
)
188180
script = _try_fix_script(script_hash, script)
189181
else:
190182
raise ValueError("Unknown plutus script type")

pycardano/backend/ogmios_v6.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
PLUTUS_V1_COST_MODEL,
2222
PLUTUS_V2_COST_MODEL,
2323
ExecutionUnits,
24-
PlutusV1Script,
25-
PlutusV2Script,
26-
PlutusV3Script,
24+
PlutusScript,
2725
)
2826
from pycardano.serialization import RawCBOR
2927
from pycardano.transaction import (
@@ -261,12 +259,11 @@ def _utxo_from_ogmios_result(self, utxo: OgmiosUtxo) -> UTxO:
261259
script = utxo.script
262260
if script:
263261
# TODO: Need to test with native scripts
264-
if script["language"] == "plutus:v3":
265-
script = PlutusV3Script(bytes.fromhex(script["cbor"]))
266-
elif script["language"] == "plutus:v2":
267-
script = PlutusV2Script(bytes.fromhex(script["cbor"]))
268-
elif script["language"] == "plutus:v1":
269-
script = PlutusV1Script(bytes.fromhex(script["cbor"]))
262+
if script["language"].startswith("plutus:v"):
263+
script = PlutusScript.from_version(
264+
int(script["language"].removeprefix("plutus:v")),
265+
bytes.fromhex(script["cbor"]),
266+
)
270267
else:
271268
raise ValueError("Unknown plutus script type")
272269
datum_hash = (

pycardano/plutus.py

+53-19
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"Datum",
4141
"RedeemerTag",
4242
"ExecutionUnits",
43+
"PlutusScript",
4344
"PlutusV1Script",
4445
"PlutusV2Script",
4546
"PlutusV3Script",
@@ -1049,33 +1050,66 @@ class RedeemerMap(DictCBORSerializable):
10491050
Redeemers = Union[List[Redeemer], RedeemerMap]
10501051

10511052

1052-
def plutus_script_hash(
1053-
script: Union[bytes, PlutusV1Script, PlutusV2Script]
1054-
) -> ScriptHash:
1053+
def plutus_script_hash(script: Union[NativeScript, PlutusScript]) -> ScriptHash:
10551054
"""Calculates the hash of a Plutus script.
10561055
10571056
Args:
1058-
script (Union[bytes, PlutusV1Script, PlutusV2Script]): A plutus script.
1057+
script (Union[bytes, PlutusScript]): A plutus script.
10591058
10601059
Returns:
10611060
ScriptHash: blake2b hash of the script.
10621061
"""
10631062
return script_hash(script)
10641063

10651064

1066-
class PlutusV1Script(bytes):
1067-
pass
1065+
class PlutusScript(bytes):
1066+
@property
1067+
def version(self) -> int:
1068+
raise NotImplementedError("")
1069+
1070+
@classmethod
1071+
def from_version(cls, version: int, script_data: bytes) -> "PlutusScript":
1072+
if version == 1:
1073+
return PlutusV1Script(script_data)
1074+
elif version == 2:
1075+
return PlutusV2Script(script_data)
1076+
elif version == 3:
1077+
return PlutusV3Script(script_data)
1078+
else:
1079+
raise ValueError(f"No Plutus script class found for version {version}")
1080+
1081+
def get_script_hash_prefix(self) -> bytes:
1082+
raise NotImplementedError("")
1083+
1084+
1085+
class PlutusV1Script(PlutusScript):
1086+
def get_script_hash_prefix(self) -> bytes:
1087+
return bytes.fromhex("01")
1088+
1089+
@property
1090+
def version(self) -> int:
1091+
return 1
10681092

10691093

1070-
class PlutusV2Script(bytes):
1071-
pass
1094+
class PlutusV2Script(PlutusScript):
1095+
def get_script_hash_prefix(self) -> bytes:
1096+
return bytes.fromhex("02")
10721097

1098+
@property
1099+
def version(self) -> int:
1100+
return 2
10731101

1074-
class PlutusV3Script(bytes):
1075-
pass
10761102

1103+
class PlutusV3Script(PlutusScript):
1104+
def get_script_hash_prefix(self) -> bytes:
1105+
return bytes.fromhex("03")
10771106

1078-
ScriptType = Union[bytes, NativeScript, PlutusV1Script, PlutusV2Script]
1107+
@property
1108+
def version(self) -> int:
1109+
return 3
1110+
1111+
1112+
ScriptType = Union[NativeScript, PlutusScript]
10791113
"""Script type. A Union type that contains all valid script types."""
10801114

10811115

@@ -1090,17 +1124,17 @@ def script_hash(script: ScriptType) -> ScriptHash:
10901124
"""
10911125
if isinstance(script, NativeScript):
10921126
return script.hash()
1093-
elif isinstance(script, PlutusV1Script) or type(script) is bytes:
1127+
elif isinstance(script, PlutusScript):
10941128
return ScriptHash(
1095-
blake2b(bytes.fromhex("01") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder)
1096-
)
1097-
elif isinstance(script, PlutusV2Script):
1098-
return ScriptHash(
1099-
blake2b(bytes.fromhex("02") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder)
1129+
blake2b(
1130+
script.get_script_hash_prefix() + script,
1131+
SCRIPT_HASH_SIZE,
1132+
encoder=RawEncoder,
1133+
)
11001134
)
1101-
elif isinstance(script, PlutusV3Script):
1135+
elif type(script) is bytes:
11021136
return ScriptHash(
1103-
blake2b(bytes.fromhex("03") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder)
1137+
blake2b(bytes.fromhex("01") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder)
11041138
)
11051139
else:
11061140
raise TypeError(f"Unexpected script type: {type(script)}")

pycardano/transaction.py

+8-24
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@
2828
from pycardano.metadata import AuxiliaryData
2929
from pycardano.nativescript import NativeScript
3030
from pycardano.network import Network
31-
from pycardano.plutus import (
32-
Datum,
33-
PlutusV1Script,
34-
PlutusV2Script,
35-
PlutusV3Script,
36-
RawPlutusData,
37-
)
31+
from pycardano.plutus import Datum, PlutusScript, RawPlutusData
3832
from pycardano.serialization import (
3933
ArrayCBORSerializable,
4034
CBORSerializable,
@@ -310,29 +304,21 @@ def to_shallow_primitive(self):
310304
class _Script(ArrayCBORSerializable):
311305
_TYPE: int = field(init=False, default=0)
312306

313-
script: Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script]
307+
script: Union[NativeScript, PlutusScript]
314308

315309
def __post_init__(self):
316310
if isinstance(self.script, NativeScript):
317311
self._TYPE = 0
318-
elif isinstance(self.script, PlutusV1Script):
319-
self._TYPE = 1
320-
elif isinstance(self.script, PlutusV2Script):
321-
self._TYPE = 2
322-
else:
323-
self._TYPE = 3
312+
elif isinstance(self.script, PlutusScript):
313+
self._TYPE = self.script.version
324314

325315
@classmethod
326316
def from_primitive(cls: Type[_Script], values: List[Primitive]) -> _Script:
327317
if values[0] == 0:
328318
return cls(NativeScript.from_primitive(values[1]))
329319
assert isinstance(values[1], bytes)
330-
if values[0] == 1:
331-
return cls(PlutusV1Script(values[1]))
332-
elif values[0] == 2:
333-
return cls(PlutusV2Script(values[1]))
334-
else:
335-
return cls(PlutusV3Script(values[1]))
320+
assert isinstance(values[0], int)
321+
return cls(PlutusScript.from_version(values[0], values[1]))
336322

337323

338324
@dataclass(repr=False)
@@ -401,7 +387,7 @@ class _TransactionOutputPostAlonzo(MapCBORSerializable):
401387
@property
402388
def script(
403389
self,
404-
) -> Optional[Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script]]:
390+
) -> Optional[Union[NativeScript, PlutusScript]]:
405391
if self.script_ref:
406392
return self.script_ref.script.script
407393
else:
@@ -427,9 +413,7 @@ class TransactionOutput(CBORSerializable):
427413

428414
datum: Optional[Datum] = None
429415

430-
script: Optional[
431-
Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script]
432-
] = None
416+
script: Optional[Union[NativeScript, PlutusScript]] = None
433417

434418
post_alonzo: Optional[bool] = False
435419

0 commit comments

Comments
 (0)