Skip to content

Commit 326b108

Browse files
authored
[CHIA-3729] Fix clvm streamable type analysis (#20031)
* Use fully recursive JSON logic for compound clvm streamable types * Accomodate rust types * Accomodate dicts * Broaden function to handle type[object] instead of type[Streamable] (with a little mypy workaround) * Whoops, delete that * Small bug * Okay a complete rework * Delete some now unused stuff * Some edge cases
1 parent 81a0a95 commit 326b108

File tree

2 files changed

+33
-44
lines changed

2 files changed

+33
-44
lines changed

chia/util/streamable.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import dataclasses
6+
import functools
67
import io
78
import os
89
import pprint
@@ -210,7 +211,7 @@ def streamable_from_dict(klass: type[_T_Streamable], item: Any) -> _T_Streamable
210211

211212

212213
def function_to_convert_one_item(
213-
f_type: type[Any], json_parser: Optional[Callable[[object], Streamable]] = None
214+
f_type: type[Any], json_parser: Optional[Callable[[object, type[object]], Streamable]] = None
214215
) -> ConvertFunctionType:
215216
if is_type_SpecificOptional(f_type):
216217
convert_inner_func = function_to_convert_one_item(get_args(f_type)[0], json_parser)
@@ -234,8 +235,9 @@ def function_to_convert_one_item(
234235
return lambda mapping: convert_dict(key_converter, value_converter, mapping) # type: ignore[arg-type]
235236
elif hasattr(f_type, "from_json_dict"):
236237
if json_parser is None:
237-
json_parser = f_type.from_json_dict
238-
return json_parser
238+
return f_type.from_json_dict # type: ignore[no-any-return]
239+
else:
240+
return functools.partial(json_parser, streamable_type=f_type) # type: ignore[call-arg]
239241
elif issubclass(f_type, bytes):
240242
# Type is bytes, data is a hex string or bytes
241243
return lambda item: convert_byte_type(f_type, item)

chia/wallet/util/clvm_streamable.py

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
import dataclasses
44
import functools
55
from types import MappingProxyType
6-
from typing import Any, Callable, Generic, Optional, TypeVar, Union, get_args, get_type_hints
6+
from typing import Any, Callable, Generic, Optional, TypeVar, Union, get_type_hints
77

88
from hsms.clvm_serde import from_program_for_type, to_program_for_type
99
from typing_extensions import TypeGuard
1010

1111
from chia.types.blockchain_format.program import Program
12+
from chia.util.byte_types import hexstr_to_bytes
1213
from chia.util.streamable import (
1314
Streamable,
1415
function_to_convert_one_item,
15-
is_type_List,
16-
is_type_SpecificOptional,
1716
is_type_Tuple,
1817
recurse_jsonify,
1918
streamable,
@@ -94,14 +93,10 @@ def byte_deserialize_clvm_streamable(
9493
)
9594

9695

97-
def is_compound_type(typ: Any) -> bool:
98-
return is_type_SpecificOptional(typ) or is_type_Tuple(typ) or is_type_List(typ)
99-
100-
10196
# TODO: this is more than _just_ a Streamable, but it is also a Streamable and that's
10297
# useful for now
103-
def is_clvm_streamable_type(v: type[object]) -> TypeGuard[type[Streamable]]:
104-
return issubclass(v, Streamable) and hasattr(v, "_clvm_streamable")
98+
def is_clvm_streamable_type(v: type[object]) -> bool:
99+
return isinstance(v, type) and issubclass(v, Streamable) and hasattr(v, "_clvm_streamable")
105100

106101

107102
# TODO: this is more than _just_ a Streamable, but it is also a Streamable and that's
@@ -115,48 +110,40 @@ def json_deserialize_with_clvm_streamable(
115110
streamable_type: type[_T_Streamable],
116111
translation_layer: Optional[TranslationLayer] = None,
117112
) -> _T_Streamable:
118-
if isinstance(json_dict, str):
113+
# This function is flawed for compound types because it's highjacking the function_to_convert_one_item func
114+
# which does not call back to it. More examination is needed.
115+
if is_clvm_streamable_type(streamable_type) and isinstance(json_dict, str):
119116
return byte_deserialize_clvm_streamable(
120-
bytes.fromhex(json_dict), streamable_type, translation_layer=translation_layer
117+
hexstr_to_bytes(json_dict), streamable_type, translation_layer=translation_layer
121118
)
122-
else:
119+
elif hasattr(streamable_type, "streamable_fields"):
123120
old_streamable_fields = streamable_type.streamable_fields()
124121
new_streamable_fields = []
125122
for old_field in old_streamable_fields:
126-
if is_compound_type(old_field.type):
127-
inner_type = get_args(old_field.type)[0]
128-
if is_clvm_streamable_type(inner_type):
129-
new_streamable_fields.append(
130-
dataclasses.replace(
131-
old_field,
132-
convert_function=function_to_convert_one_item(
133-
old_field.type,
134-
functools.partial(
135-
json_deserialize_with_clvm_streamable,
136-
streamable_type=inner_type,
137-
translation_layer=translation_layer,
138-
),
139-
),
140-
)
141-
)
142-
else:
143-
new_streamable_fields.append(old_field)
144-
elif is_clvm_streamable_type(old_field.type):
145-
new_streamable_fields.append(
146-
dataclasses.replace(
147-
old_field,
148-
convert_function=functools.partial(
123+
new_streamable_fields.append(
124+
dataclasses.replace(
125+
old_field,
126+
convert_function=function_to_convert_one_item(
127+
old_field.type,
128+
functools.partial(
149129
json_deserialize_with_clvm_streamable,
150-
streamable_type=old_field.type,
151130
translation_layer=translation_layer,
152131
),
153-
)
132+
),
154133
)
155-
else:
156-
new_streamable_fields.append(old_field)
157-
134+
)
158135
setattr(streamable_type, "_streamable_fields", tuple(new_streamable_fields))
159-
return streamable_type.from_json_dict(json_dict)
136+
return streamable_type.from_json_dict(json_dict) # type: ignore[arg-type]
137+
elif hasattr(streamable_type, "from_json_dict"):
138+
return streamable_type.from_json_dict(json_dict) # type: ignore[arg-type]
139+
else:
140+
return function_to_convert_one_item( # type: ignore[return-value]
141+
streamable_type,
142+
functools.partial(
143+
json_deserialize_with_clvm_streamable,
144+
translation_layer=translation_layer,
145+
),
146+
)(json_dict)
160147

161148

162149
_T_ClvmStreamable = TypeVar("_T_ClvmStreamable", bound="Streamable")

0 commit comments

Comments
 (0)