mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-19 23:21:46 +03:00
util: Some tweaks to StructStream
and sized ints (#15090)
* Only define `StructStream` members, don't give them defaults * `MAXIMUM_EXCLUSIVE` -> `MAXIMUM` * Make `MINIMUM` and `MAXIMUM` instances of the underlying class * Make the `StructStream` members `ClassVar`s * More explicit and consistent `MINIMUM` and `MAXIMUM` assignments * Comment about instantiation * Use `MAXIMUM`
This commit is contained in:
parent
b2498d2917
commit
508087251c
@ -2926,10 +2926,7 @@ class WalletRpcApi:
|
||||
async def get_coin_records(self, request: Dict[str, Any]) -> EndpointResult:
|
||||
parsed_request = GetCoinRecords.from_json_dict(request)
|
||||
|
||||
if (
|
||||
parsed_request.limit != uint32.MAXIMUM_EXCLUSIVE - 1
|
||||
and parsed_request.limit > self.max_get_coin_records_limit
|
||||
):
|
||||
if parsed_request.limit != uint32.MAXIMUM and parsed_request.limit > self.max_get_coin_records_limit:
|
||||
raise ValueError(f"limit of {self.max_get_coin_records_limit} exceeded: {parsed_request.limit}")
|
||||
|
||||
for filter_name, filter in {
|
||||
|
@ -1,51 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import ClassVar
|
||||
|
||||
from chia.util.struct_stream import StructStream, parse_metadata_from_name
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class int8(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[int8]
|
||||
MAXIMUM: ClassVar[int8]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class uint8(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[uint8]
|
||||
MAXIMUM: ClassVar[uint8]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class int16(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[int16]
|
||||
MAXIMUM: ClassVar[int16]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class uint16(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[uint16]
|
||||
MAXIMUM: ClassVar[uint16]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class int32(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[int32]
|
||||
MAXIMUM: ClassVar[int32]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class uint32(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[uint32]
|
||||
MAXIMUM: ClassVar[uint32]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class int64(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[int64]
|
||||
MAXIMUM: ClassVar[int64]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class uint64(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[uint64]
|
||||
MAXIMUM: ClassVar[uint64]
|
||||
|
||||
|
||||
@parse_metadata_from_name
|
||||
class uint128(StructStream):
|
||||
pass
|
||||
MINIMUM: ClassVar[uint128]
|
||||
MAXIMUM: ClassVar[uint128]
|
||||
|
||||
|
||||
class int512(StructStream):
|
||||
@ -59,5 +70,9 @@ class int512(StructStream):
|
||||
# note that the boundaries for int512 is not what you might expect. We
|
||||
# encode these with one extra byte, but only allow a range of
|
||||
# [-INT512_MAX, INT512_MAX]
|
||||
MAXIMUM_EXCLUSIVE = 2**BITS
|
||||
MINIMUM = -(2**BITS) + 1
|
||||
MINIMUM: ClassVar[int512] = -(2**BITS) + 1
|
||||
MAXIMUM: ClassVar[int512] = (2**BITS) - 1
|
||||
|
||||
|
||||
int512.MINIMUM = int512(int512.MINIMUM)
|
||||
int512.MAXIMUM = int512(int512.MAXIMUM)
|
||||
|
@ -124,14 +124,14 @@ else:
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class UInt32Range(Streamable):
|
||||
start: uint32 = uint32(0)
|
||||
stop: uint32 = uint32(uint32.MAXIMUM_EXCLUSIVE - 1)
|
||||
stop: uint32 = uint32.MAXIMUM
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class UInt64Range(Streamable):
|
||||
start: uint64 = uint64(0)
|
||||
stop: uint64 = uint64(uint64.MAXIMUM_EXCLUSIVE - 1)
|
||||
stop: uint64 = uint64.MAXIMUM
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import BinaryIO, SupportsInt, Type, TypeVar, Union
|
||||
from typing import BinaryIO, ClassVar, SupportsInt, Type, TypeVar, Union
|
||||
|
||||
from typing_extensions import Protocol, SupportsIndex
|
||||
|
||||
@ -37,24 +37,28 @@ def parse_metadata_from_name(cls: Type[_T_StructStream]) -> Type[_T_StructStream
|
||||
raise ValueError(f"cls.BITS must be a multiple of 8: {cls.BITS}")
|
||||
|
||||
if cls.SIGNED:
|
||||
cls.MAXIMUM_EXCLUSIVE = 2 ** (cls.BITS - 1)
|
||||
cls.MINIMUM = -(2 ** (cls.BITS - 1))
|
||||
cls.MAXIMUM = (2 ** (cls.BITS - 1)) - 1
|
||||
else:
|
||||
cls.MAXIMUM_EXCLUSIVE = 2**cls.BITS
|
||||
cls.MINIMUM = 0
|
||||
cls.MAXIMUM = (2**cls.BITS) - 1
|
||||
|
||||
cls.MINIMUM = cls(cls.MINIMUM)
|
||||
cls.MAXIMUM = cls(cls.MAXIMUM)
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
class StructStream(int):
|
||||
SIZE = 0
|
||||
BITS = 0
|
||||
SIGNED = False
|
||||
MAXIMUM_EXCLUSIVE = 0
|
||||
MINIMUM = 0
|
||||
SIZE: ClassVar[int]
|
||||
BITS: ClassVar[int]
|
||||
SIGNED: ClassVar[bool]
|
||||
MAXIMUM: ClassVar[int]
|
||||
MINIMUM: ClassVar[int]
|
||||
|
||||
"""
|
||||
Create a class that can parse and stream itself based on a struct.pack template string.
|
||||
Create a class that can parse and stream itself based on a struct.pack template string. This is only meant to be
|
||||
a base class for further derivation and it's not recommended to instantiate it directly.
|
||||
"""
|
||||
|
||||
# This is just a partial exposure of the underlying int constructor. Liskov...
|
||||
@ -65,7 +69,7 @@ class StructStream(int):
|
||||
# additional special action to take here beyond verifying that the newly
|
||||
# created instance satisfies the bounds limitations of the particular subclass.
|
||||
super().__init__()
|
||||
if not (self.MINIMUM <= self < self.MAXIMUM_EXCLUSIVE):
|
||||
if not (self.MINIMUM <= self <= self.MAXIMUM):
|
||||
raise ValueError(f"Value {self} does not fit into {type(self).__name__}")
|
||||
|
||||
@classmethod
|
||||
|
@ -29,7 +29,7 @@ class CoinRecordOrder(IntEnum):
|
||||
@dataclass(frozen=True)
|
||||
class GetCoinRecords(Streamable):
|
||||
offset: uint32 = uint32(0)
|
||||
limit: uint32 = uint32(uint32.MAXIMUM_EXCLUSIVE - 1)
|
||||
limit: uint32 = uint32.MAXIMUM
|
||||
wallet_id: Optional[uint32] = None
|
||||
wallet_type: Optional[uint8] = None # WalletType
|
||||
coin_type: Optional[uint8] = None # CoinType
|
||||
@ -188,7 +188,7 @@ class WalletCoinStore:
|
||||
self,
|
||||
*,
|
||||
offset: uint32 = uint32(0),
|
||||
limit: uint32 = uint32(uint32.MAXIMUM_EXCLUSIVE - 1),
|
||||
limit: uint32 = uint32.MAXIMUM,
|
||||
wallet_id: Optional[uint32] = None,
|
||||
wallet_type: Optional[WalletType] = None,
|
||||
coin_type: Optional[CoinType] = None,
|
||||
@ -237,7 +237,7 @@ class WalletCoinStore:
|
||||
|
||||
where_sql = "WHERE " + " AND ".join(conditions) if len(conditions) > 0 else ""
|
||||
order_sql = f"ORDER BY {order.name} {'DESC' if reverse else 'ASC'}, rowid"
|
||||
limit_sql = f"LIMIT {offset}, {limit}" if offset > 0 or limit < uint32.MAXIMUM_EXCLUSIVE - 1 else ""
|
||||
limit_sql = f"LIMIT {offset}, {limit}" if offset > 0 or limit < uint32.MAXIMUM else ""
|
||||
query_sql = f"{where_sql} {order_sql} {limit_sql}"
|
||||
|
||||
async with self.db_wrapper.reader_no_transaction() as conn:
|
||||
|
@ -41,7 +41,7 @@ class Good:
|
||||
size: int
|
||||
bits: int
|
||||
signed: bool
|
||||
maximum_exclusive: int
|
||||
maximum: int
|
||||
minimum: int
|
||||
|
||||
@classmethod
|
||||
@ -50,7 +50,7 @@ class Good:
|
||||
name: str,
|
||||
size: int,
|
||||
signed: bool,
|
||||
maximum_exclusive: int,
|
||||
maximum: int,
|
||||
minimum: int,
|
||||
) -> Good:
|
||||
raw_class: Type[StructStream] = type(name, (StructStream,), {})
|
||||
@ -61,30 +61,30 @@ class Good:
|
||||
size=size,
|
||||
bits=size * 8,
|
||||
signed=signed,
|
||||
maximum_exclusive=maximum_exclusive,
|
||||
maximum=maximum,
|
||||
minimum=minimum,
|
||||
)
|
||||
|
||||
|
||||
good_classes = [
|
||||
Good.create(name="uint8", size=1, signed=False, maximum_exclusive=0xFF + 1, minimum=0),
|
||||
Good.create(name="int8", size=1, signed=True, maximum_exclusive=0x80, minimum=-0x80),
|
||||
Good.create(name="uint16", size=2, signed=False, maximum_exclusive=0xFFFF + 1, minimum=0),
|
||||
Good.create(name="int16", size=2, signed=True, maximum_exclusive=0x8000, minimum=-0x8000),
|
||||
Good.create(name="uint24", size=3, signed=False, maximum_exclusive=0xFFFFFF + 1, minimum=0),
|
||||
Good.create(name="int24", size=3, signed=True, maximum_exclusive=0x800000, minimum=-0x800000),
|
||||
Good.create(name="uint8", size=1, signed=False, maximum=0xFF, minimum=0),
|
||||
Good.create(name="int8", size=1, signed=True, maximum=0x7F, minimum=-0x80),
|
||||
Good.create(name="uint16", size=2, signed=False, maximum=0xFFFF, minimum=0),
|
||||
Good.create(name="int16", size=2, signed=True, maximum=0x7FFF, minimum=-0x8000),
|
||||
Good.create(name="uint24", size=3, signed=False, maximum=0xFFFFFF, minimum=0),
|
||||
Good.create(name="int24", size=3, signed=True, maximum=0x7FFFFF, minimum=-0x800000),
|
||||
Good.create(
|
||||
name="uint128",
|
||||
size=16,
|
||||
signed=False,
|
||||
maximum_exclusive=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 1,
|
||||
maximum=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
|
||||
minimum=0,
|
||||
),
|
||||
Good.create(
|
||||
name="int128",
|
||||
size=16,
|
||||
signed=True,
|
||||
maximum_exclusive=0x80000000000000000000000000000000,
|
||||
maximum=0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
|
||||
minimum=-0x80000000000000000000000000000000,
|
||||
),
|
||||
]
|
||||
@ -145,6 +145,9 @@ class TestStructStream:
|
||||
with pytest.raises(struct.error):
|
||||
struct.pack(struct_format, upper_boundary + 1)
|
||||
|
||||
assert type(cls.MINIMUM) == cls
|
||||
assert type(cls.MAXIMUM) == cls
|
||||
|
||||
def test_int512(self) -> None:
|
||||
# int512 is special. it uses 65 bytes to allow positive and negative
|
||||
# "uint512"
|
||||
@ -245,7 +248,7 @@ class TestStructStream:
|
||||
assert uint32(b"273") == 273
|
||||
|
||||
def test_struct_stream_cannot_be_instantiated_directly(self) -> None:
|
||||
with pytest.raises(ValueError, match="does not fit"):
|
||||
with pytest.raises(AttributeError, match="object has no attribute"):
|
||||
StructStream(0)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -281,7 +284,7 @@ class TestStructStream:
|
||||
assert good.cls.SIGNED == good.signed
|
||||
|
||||
def test_parse_metadata_from_name_correct_maximum(self, good: Good) -> None:
|
||||
assert good.cls.MAXIMUM_EXCLUSIVE == good.maximum_exclusive
|
||||
assert good.cls.MAXIMUM == good.maximum
|
||||
|
||||
def test_parse_metadata_from_name_correct_minimum(self, good: Good) -> None:
|
||||
assert good.cls.MINIMUM == good.minimum
|
||||
|
Loading…
Reference in New Issue
Block a user