|
| 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