Skip to content

Commit c976bce

Browse files
committed
Check size of metadata
1 parent 878e1f8 commit c976bce

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

pycardano/metadata.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from nacl.encoding import RawEncoder
88
from nacl.hash import blake2b
99

10-
from pycardano.exception import DeserializeException
10+
from pycardano.exception import DeserializeException, InvalidArgumentException
1111
from pycardano.hash import AuxiliaryDataHash, AUXILIARY_DATA_HASH_SIZE
1212
from pycardano.nativescript import NativeScript
1313
from pycardano.serialization import (CBORSerializable, DictCBORSerializable, ArrayCBORSerializable,
@@ -18,6 +18,38 @@ class Metadata(DictCBORSerializable):
1818
KEY_TYPE = int # transaction_metadatum_label, see https://github.com/cardano-foundation/CIPs/tree/master/CIP-0010
1919
VALUE_TYPE = Any
2020

21+
MAX_ITEM_SIZE = 64
22+
INTERNAL_TYPES = (dict, list, int, bytes, str)
23+
24+
def _validate(self):
25+
26+
def _validate_type_and_size(data):
27+
if not isinstance(data, self.INTERNAL_TYPES):
28+
raise InvalidArgumentException(f"A value in Metadata has to be one of {self.INTERNAL_TYPES}, "
29+
f"got {type(data)} instead.")
30+
if isinstance(data, bytes):
31+
if len(data) > self.MAX_ITEM_SIZE:
32+
raise InvalidArgumentException(f"The size of {data} exceeds {self.MAX_ITEM_SIZE} bytes.")
33+
elif isinstance(data, str):
34+
if len(data.encode("utf-8")) > self.MAX_ITEM_SIZE:
35+
raise InvalidArgumentException(f"The size of {data} exceeds {self.MAX_ITEM_SIZE} bytes.")
36+
elif isinstance(data, list):
37+
for item in data:
38+
_validate_type_and_size(item)
39+
elif isinstance(data, dict):
40+
for key in data:
41+
_validate_type_and_size(data[key])
42+
43+
for k in self:
44+
if not isinstance(k, self.KEY_TYPE):
45+
raise InvalidArgumentException(f"Keys in the first layer of Metadata has to be {self.KEY_TYPE}, "
46+
f"got {type(k)} instead.")
47+
_validate_type_and_size(self[k])
48+
49+
def __init__(self, *args, **kwargs):
50+
super().__init__(*args, **kwargs)
51+
self._validate()
52+
2153

2254
@dataclass
2355
class ShellayMarryMetadata(ArrayCBORSerializable):

test/pycardano/test_metadata.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import pytest
12
from cbor2 import CBORTag
23

4+
from pycardano.exception import InvalidArgumentException
35
from pycardano.key import VerificationKey
46
from pycardano.metadata import Metadata, ShellayMarryMetadata, AlonzoMetadata, AuxiliaryData
57
from pycardano.nativescript import ScriptPubkey, ScriptAll, InvalidBefore, InvalidHereAfter
@@ -92,3 +94,49 @@ def test_axuiliary_data_hash():
9294

9395
aux_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(data)))
9496
assert "592a2df0e091566969b3044626faa8023dabe6f39c78f33bed9e105e55159221" == str(aux_data.hash())
97+
98+
99+
def test_metadata_invalid_type():
100+
data = {
101+
"abc": "abc"
102+
}
103+
with pytest.raises(InvalidArgumentException):
104+
Metadata(data)
105+
106+
data = {
107+
123: {
108+
"1": set()
109+
}
110+
}
111+
with pytest.raises(InvalidArgumentException):
112+
Metadata(data)
113+
114+
115+
def test_metadata_valid_size():
116+
data = {
117+
123: {
118+
"1": bytes(Metadata.MAX_ITEM_SIZE),
119+
"2": "1" * Metadata.MAX_ITEM_SIZE
120+
}
121+
}
122+
Metadata(data)
123+
124+
125+
def test_metadata_invalid_size():
126+
data = {
127+
123: {
128+
"1": bytes(Metadata.MAX_ITEM_SIZE + 1)
129+
}
130+
}
131+
132+
with pytest.raises(InvalidArgumentException):
133+
Metadata(data)
134+
135+
data = {
136+
123: {
137+
"1": "1" * (Metadata.MAX_ITEM_SIZE + 1)
138+
}
139+
}
140+
141+
with pytest.raises(InvalidArgumentException):
142+
Metadata(data)

0 commit comments

Comments
 (0)