diff --git a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py index 503926517..9d7138d7d 100644 --- a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py @@ -41,11 +41,15 @@ def merkleize_chunks(chunks, limit=None): # If no limit is defined, we are just merkleizing chunks (e.g. SSZ container). if limit is None: limit = len(chunks) + + count = len(chunks) + # See if the input is within expected size. + # If not, a list-limit is set incorrectly, or a value is unexpectedly large. + assert count <= limit + if limit == 0: return zerohashes[0] - # Limit strictly. Makes no sense to merkleize objects above the intended padding. - # And illegal to exceed list limits, just as with serialization. - count = min(len(chunks), limit) + depth = max(count - 1, 0).bit_length() max_depth = (limit - 1).bit_length() tmp = [None for _ in range(max_depth + 1)] diff --git a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py index a40ec05cf..3746ea6ca 100644 --- a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py @@ -19,24 +19,24 @@ def z(i: int) -> bytes: cases = [ # limit 0: always zero hash (0, 0, z(0)), - (1, 0, z(0)), # cut-off due to limit - (2, 0, z(0)), # cut-off due to limit + (1, 0, None), # cut-off due to limit + (2, 0, None), # cut-off due to limit # limit 1: padded to 1 element if not already. Returned (like identity func) (0, 1, z(0)), (1, 1, e(0)), - (2, 1, e(0)), # cut-off due to limit + (2, 1, None), # cut-off due to limit (1, 1, e(0)), (0, 2, h(z(0), z(0))), (1, 2, h(e(0), z(0))), (2, 2, h(e(0), e(1))), - (3, 2, h(e(0), e(1))), # cut-off due to limit - (16, 2, h(e(0), e(1))), # bigger cut-off due to limit + (3, 2, None), # cut-off due to limit + (16, 2, None), # bigger cut-off due to limit (0, 4, h(h(z(0), z(0)), z(1))), (1, 4, h(h(e(0), z(0)), z(1))), (2, 4, h(h(e(0), e(1)), z(1))), (3, 4, h(h(e(0), e(1)), h(e(2), z(0)))), (4, 4, h(h(e(0), e(1)), h(e(2), e(3)))), - (5, 4, h(h(e(0), e(1)), h(e(2), e(3)))), # cut-off due to limit + (5, 4, None), # cut-off due to limit (0, 8, h(h(h(z(0), z(0)), z(1)), z(2))), (1, 8, h(h(h(e(0), z(0)), z(1)), z(2))), (2, 8, h(h(h(e(0), e(1)), z(1)), z(2))), @@ -46,7 +46,7 @@ cases = [ (6, 8, h(h(h(e(0), e(1)), h(e(2), e(3))), h(h(e(4), e(5)), h(z(0), z(0))))), (7, 8, h(h(h(e(0), e(1)), h(e(2), e(3))), h(h(e(4), e(5)), h(e(6), z(0))))), (8, 8, h(h(h(e(0), e(1)), h(e(2), e(3))), h(h(e(4), e(5)), h(e(6), e(7))))), - (9, 8, h(h(h(e(0), e(1)), h(e(2), e(3))), h(h(e(4), e(5)), h(e(6), e(7))))), # cut-off due to limit + (9, 8, None), # cut-off due to limit (0, 16, h(h(h(h(z(0), z(0)), z(1)), z(2)), z(3))), (1, 16, h(h(h(h(e(0), z(0)), z(1)), z(2)), z(3))), (2, 16, h(h(h(h(e(0), e(1)), z(1)), z(2)), z(3))), @@ -66,5 +66,15 @@ cases = [ ) def test_merkleize_chunks_and_get_merkle_root(count, limit, value): chunks = [e(i) for i in range(count)] - assert merkleize_chunks(chunks, limit=limit) == value - assert get_merkle_root(chunks, pad_to=limit) == value + if value is None: + bad = False + try: + merkleize_chunks(chunks, limit=limit) + bad = True + except AssertionError: + pass + if bad: + assert False, "expected merkleization to be invalid" + else: + assert merkleize_chunks(chunks, limit=limit) == value + assert get_merkle_root(chunks, pad_to=limit) == value