33from __future__ import annotations
44
55from dataclasses import dataclass , field
6- from typing import List , Union
6+ from typing import ClassVar , List , Union
77
88from nacl .encoding import RawEncoder
99from nacl .hash import blake2b
@@ -52,16 +52,80 @@ def hash(self) -> ScriptHash:
5252 )
5353 )
5454
55+ @classmethod
56+ def from_dict (
57+ cls : NativeScript , script : dict , top_level : bool = True
58+ ) -> Union [
59+ ScriptPubkey , ScriptAll , ScriptAny , ScriptNofK , InvalidBefore , InvalidHereAfter
60+ ]:
61+ """Parse a standard native script dictionary (potentially parsed from a JSON file)."""
62+
63+ types = {
64+ p .json_tag : p
65+ for p in [
66+ ScriptPubkey ,
67+ ScriptAll ,
68+ ScriptAny ,
69+ ScriptNofK ,
70+ InvalidBefore ,
71+ InvalidHereAfter ,
72+ ]
73+ }
74+
75+ if isinstance (script , dict ):
76+ native_script = []
77+
78+ for key , value in script .items ():
79+ if key == "type" :
80+ native_script .insert (0 , list (types .keys ()).index (value ))
81+ elif key == "scripts" :
82+ native_script .append (cls .from_dict (value , top_level = False ))
83+ else :
84+ native_script .append (value )
85+
86+ elif isinstance (script , list ): # list
87+ native_script = [cls .from_dict (i , top_level = False ) for i in script ]
88+
89+ if not top_level :
90+ return native_script
91+ else :
92+ return super (NativeScript , types [script ["type" ]]).from_primitive (
93+ native_script [1 :]
94+ )
95+
96+ def to_dict (self ) -> dict :
97+ """Export to standard native script dictionary (potentially to dump to a JSON file)."""
98+
99+ script = {}
100+
101+ for value in self .__dict__ .values ():
102+ script ["type" ] = self .json_tag
103+
104+ if isinstance (value , list ):
105+ script ["scripts" ] = [i .to_dict () for i in value ]
106+
107+ else :
108+ if isinstance (value , int ):
109+ script [self .json_field ] = value
110+ else :
111+ script [self .json_field ] = str (value )
112+
113+ return script
114+
55115
56116@dataclass
57117class ScriptPubkey (NativeScript ):
118+ json_tag : ClassVar [str ] = "sig"
119+ json_field : ClassVar [str ] = "keyHash"
58120 _TYPE : int = field (default = 0 , init = False )
59121
60122 key_hash : VerificationKeyHash
61123
62124
63125@dataclass
64126class ScriptAll (NativeScript ):
127+ json_tag : ClassVar [str ] = "all"
128+ json_field : ClassVar [str ] = "scripts"
65129 _TYPE : int = field (default = 1 , init = False )
66130
67131 native_scripts : List [
@@ -78,6 +142,8 @@ class ScriptAll(NativeScript):
78142
79143@dataclass
80144class ScriptAny (NativeScript ):
145+ json_tag : ClassVar [str ] = "any"
146+ json_field : ClassVar [str ] = "scripts"
81147 _TYPE : int = field (default = 2 , init = False )
82148
83149 native_scripts : List [
@@ -94,6 +160,8 @@ class ScriptAny(NativeScript):
94160
95161@dataclass
96162class ScriptNofK (NativeScript ):
163+ json_tag : ClassVar [str ] = "atLeast"
164+ json_field : ClassVar [str ] = "required"
97165 _TYPE : int = field (default = 3 , init = False )
98166
99167 n : int
@@ -112,13 +180,17 @@ class ScriptNofK(NativeScript):
112180
113181@dataclass
114182class InvalidBefore (NativeScript ):
183+ json_tag : ClassVar [str ] = "after"
184+ json_field : ClassVar [str ] = "slot"
115185 _TYPE : int = field (default = 4 , init = False )
116186
117187 before : int = None
118188
119189
120190@dataclass
121191class InvalidHereAfter (NativeScript ):
192+ json_tag : ClassVar [str ] = "before"
193+ json_field : ClassVar [str ] = "slot"
122194 _TYPE : int = field (default = 5 , init = False )
123195
124196 after : int = None
0 commit comments