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:
parent
0929d90d93
commit
0d54073ec9
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue