properly work around nim type bug in ssz

the cast worked around the bug at compile time by means of casting, but
introduced a runtime error, because the pre-cast type was still being
used during deserialization
This commit is contained in:
Jacek Sieka 2020-05-25 16:42:01 +02:00 committed by zah
parent 0929d90d93
commit 0d54073ec9
1 changed files with 16 additions and 23 deletions

View File

@ -6,9 +6,6 @@ import
stew/[bitseqs, endians2, objects, bitseqs], serialization/testing/tracing, stew/[bitseqs, endians2, objects, bitseqs], serialization/testing/tracing,
../spec/[digest, datatypes], ./types ../spec/[digest, datatypes], ./types
const
maxListAllocation = 1 * 1024 * 1024 * 1024 # 1 GiB
template raiseIncorrectSize(T: type) = template raiseIncorrectSize(T: type) =
const typeName = name(T) const typeName = name(T)
raise newException(MalformedSszError, raise newException(MalformedSszError,
@ -18,7 +15,7 @@ template setOutputSize[R, T](a: var array[R, T], length: int) =
if length != a.len: if length != a.len:
raiseIncorrectSize a.type raiseIncorrectSize a.type
proc setOutputSize(list: var List, length: int) {.inline, raisesssz.} = proc setOutputSize(list: var List, length: int) {.raisesssz.} =
if int64(length) > list.maxLen: if int64(length) > list.maxLen:
raise newException(MalformedSszError, "SSZ list maximum size exceeded") raise newException(MalformedSszError, "SSZ list maximum size exceeded")
list.setLen length list.setLen length
@ -200,8 +197,14 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} =
const boundingOffsets = T.getFieldBoundingOffsets(fieldName) const boundingOffsets = T.getFieldBoundingOffsets(fieldName)
trs "BOUNDING OFFSET FOR FIELD ", fieldName, " = ", boundingOffsets trs "BOUNDING OFFSET FOR FIELD ", fieldName, " = ", boundingOffsets
type FieldType = type field # type FieldType = type field # buggy
type SszType = type toSszType(declval FieldType) # For some reason, Nim gets confused about the alias here. This could be a
# generics caching issue caused by the use of distinct types. Such an
# issue is very scary in general.
# The bug can be seen with the two List[uint64, N] types that exist in
# the spec, with different N.
type SszType = type toSszType(declval type(field))
when isFixedSize(SszType): when isFixedSize(SszType):
const const
@ -222,30 +225,20 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} =
raise newException(MalformedSszError, "SSZ field offset points outside bounding offsets") raise newException(MalformedSszError, "SSZ field offset points outside bounding offsets")
# TODO The extra type escaping here is a work-around for a Nim issue: # TODO The extra type escaping here is a work-around for a Nim issue:
when type(FieldType) is type(SszType): when type(field) is type(SszType):
trs "READING NATIVE ", fieldName, ": ", name(SszType) trs "READING NATIVE ", fieldName, ": ", name(SszType)
field = typeof(field) readSszValue(
input.toOpenArray(startOffset, endOffset - 1),
SszType)
trs "READING COMPLETE ", fieldName
elif FieldType is List: # TODO passing in `FieldType` instead of `type(field)` triggers a
# TODO # bug in the compiler
# The `typeof(field)` coercion below is required to deal with a Nim field = readSszValue(
# bug. For some reason, Nim gets confused about the type of the list
# returned from the `readSszValue` function. This could be a generics
# caching issue caused by the use of distinct types. Such an issue
# would be very scary in general, but in this particular situation
# it shouldn't matter, because the different flavours of `List[T, N]`
# won't produce different serializations.
field = typeof(field) readSszValue(
input.toOpenArray(startOffset, endOffset - 1), input.toOpenArray(startOffset, endOffset - 1),
FieldType) type(field))
trs "READING COMPLETE ", fieldName
else: else:
trs "READING FOREIGN ", fieldName, ": ", name(SszType) trs "READING FOREIGN ", fieldName, ": ", name(SszType)
field = fromSszBytes( field = fromSszBytes(
FieldType, type(field),
input.toOpenArray(startOffset, endOffset - 1)) input.toOpenArray(startOffset, endOffset - 1))
else: else: