Skip to content

Commit e593900

Browse files
authored
Merge pull request #67 from OpShin/example/simple_scripts
Simple script emulator
2 parents 2c1bc1c + 5466faa commit e593900

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from eopsin.prelude import *
2+
3+
4+
@dataclass()
5+
class RequireSignature(PlutusData):
6+
CONSTR_ID = 0
7+
vkeyhash: bytes # this is either a PubKeyHash or a VerificationKeyHash
8+
9+
10+
@dataclass()
11+
class RequireAllOf(PlutusData):
12+
CONSTR_ID = 1
13+
scripts: List[Datum] # "Script"
14+
15+
16+
@dataclass()
17+
class RequireAnyOf(PlutusData):
18+
CONSTR_ID = 2
19+
scripts: List[Datum] # "Script"
20+
21+
22+
@dataclass()
23+
class RequireMOf(PlutusData):
24+
CONSTR_ID = 3
25+
num: int
26+
scripts: List[Datum] # "Script"
27+
28+
29+
@dataclass()
30+
class RequireBefore(PlutusData):
31+
CONSTR_ID = 4
32+
unixtimestamp: int
33+
34+
35+
@dataclass()
36+
class RequireAfter(PlutusData):
37+
CONSTR_ID = 5
38+
unixtimestamp: int
39+
40+
41+
Script = Union[
42+
RequireSignature,
43+
RequireMOf,
44+
RequireAnyOf,
45+
RequireAllOf,
46+
RequireAfter,
47+
RequireBefore,
48+
]
49+
50+
51+
def validate_script(
52+
script_raw: Datum, signatories: List[bytes], valid_range: POSIXTimeRange
53+
) -> bool:
54+
script: Script = script_raw # cast to Script in the type system to avoid recursive type definition
55+
if isinstance(script, RequireSignature):
56+
res = script.vkeyhash in signatories
57+
elif isinstance(script, RequireAllOf):
58+
res = all(
59+
[validate_script(s, signatories, valid_range) for s in script.scripts]
60+
)
61+
elif isinstance(script, RequireAnyOf):
62+
res = any(
63+
[validate_script(s, signatories, valid_range) for s in script.scripts]
64+
)
65+
elif isinstance(script, RequireMOf):
66+
res = (
67+
sum(
68+
[
69+
1 if validate_script(s, signatories, valid_range) else 0
70+
for s in script.scripts
71+
]
72+
)
73+
>= script.num
74+
)
75+
elif isinstance(script, RequireBefore):
76+
upper_bound = valid_range.upper_bound
77+
upper_limit = upper_bound.limit
78+
if isinstance(upper_limit, FinitePOSIXTime):
79+
upper_closed = upper_bound.closed
80+
if isinstance(upper_closed, TrueData):
81+
res = upper_limit.time <= script.unixtimestamp
82+
else:
83+
res = upper_limit.time < script.unixtimestamp
84+
elif isinstance(upper_limit, PosInfPOSIXTime):
85+
res = False
86+
elif isinstance(upper_limit, NegInfPOSIXTime):
87+
res = True
88+
elif isinstance(script, RequireAfter):
89+
lower_bound = valid_range.lower_bound
90+
lower_limit = lower_bound.limit
91+
if isinstance(lower_limit, FinitePOSIXTime):
92+
lower_closed = lower_bound.closed
93+
if isinstance(lower_closed, TrueData):
94+
res = lower_limit.time >= script.unixtimestamp
95+
else:
96+
res = lower_limit.time > script.unixtimestamp
97+
elif isinstance(lower_limit, PosInfPOSIXTime):
98+
res = True
99+
elif isinstance(lower_limit, NegInfPOSIXTime):
100+
res = False
101+
else:
102+
assert False, "Invalid simple script passed"
103+
return res
104+
105+
106+
# to fully emulate simple script behaviour, compile with --force-three-params
107+
# the script is a contract parameter, pass it into the build command
108+
def validator(
109+
script: Script, datum: None, redeemer: None, context: ScriptContext
110+
) -> None:
111+
assert validate_script(
112+
script, context.tx_info.signatories, context.tx_info.valid_range
113+
), "Simple Script validation failed!"

0 commit comments

Comments
 (0)