Decoding fails gracefully in several error cases
This commit is contained in:
parent
a43c7b21a4
commit
51da2802aa
|
@ -45,23 +45,37 @@ func updateLast(decoder: var AbiDecoder, index: int) =
|
||||||
func advance(decoder: var AbiDecoder, amount: int): ?!void =
|
func advance(decoder: var AbiDecoder, amount: int): ?!void =
|
||||||
decoder.index += amount
|
decoder.index += amount
|
||||||
decoder.updateLast(decoder.index)
|
decoder.updateLast(decoder.index)
|
||||||
|
if decoder.index <= decoder.bytes.len:
|
||||||
|
success()
|
||||||
|
else:
|
||||||
|
failure "reading past end"
|
||||||
|
|
||||||
|
func skipPadding(decoder: var AbiDecoder, amount: int): ?!void =
|
||||||
|
let index = decoder.index
|
||||||
|
?decoder.advance(amount)
|
||||||
|
for i in index..<index+amount:
|
||||||
|
if decoder.bytes[i] != 0:
|
||||||
|
return failure "invalid padding found"
|
||||||
success()
|
success()
|
||||||
|
|
||||||
func read(decoder: var AbiDecoder, amount: int, padding=padLeft): ?!seq[byte] =
|
func read(decoder: var AbiDecoder, amount: int, padding=padLeft): ?!seq[byte] =
|
||||||
let padlen = (32 - amount mod 32) mod 32
|
let padlen = (32 - amount mod 32) mod 32
|
||||||
if padding == padLeft:
|
if padding == padLeft:
|
||||||
?decoder.advance(padlen)
|
?decoder.skipPadding(padlen)
|
||||||
let index = decoder.index
|
let index = decoder.index
|
||||||
?decoder.advance(amount)
|
?decoder.advance(amount)
|
||||||
result = success decoder.bytes[index..<index+amount]
|
result = success decoder.bytes[index..<index+amount]
|
||||||
if padding == padRight:
|
if padding == padRight:
|
||||||
?decoder.advance(padlen)
|
?decoder.skipPadding(padlen)
|
||||||
|
|
||||||
func decode(decoder: var AbiDecoder, T: type UInt): ?!T =
|
func decode(decoder: var AbiDecoder, T: type UInt): ?!T =
|
||||||
success T.fromBytesBE(?decoder.read(sizeof(T)))
|
success T.fromBytesBE(?decoder.read(sizeof(T)))
|
||||||
|
|
||||||
func decode(decoder: var AbiDecoder, T: type bool): ?!T =
|
func decode(decoder: var AbiDecoder, T: type bool): ?!T =
|
||||||
success (?decoder.read(uint8) != 0)
|
case ?decoder.read(uint8)
|
||||||
|
of 0: success false
|
||||||
|
of 1: success true
|
||||||
|
else: failure "invalid boolean value"
|
||||||
|
|
||||||
func decode(decoder: var AbiDecoder, T: type enum): ?!T =
|
func decode(decoder: var AbiDecoder, T: type enum): ?!T =
|
||||||
success T(?decoder.read(uint64))
|
success T(?decoder.read(uint64))
|
||||||
|
@ -115,10 +129,13 @@ func decode[T: tuple](decoder: var AbiDecoder, _: typedesc[T]): ?!T =
|
||||||
func read*(decoder: var AbiDecoder, T: type): ?!T =
|
func read*(decoder: var AbiDecoder, T: type): ?!T =
|
||||||
decoder.decode(T)
|
decoder.decode(T)
|
||||||
|
|
||||||
func finish(decoder: var AbiDecoder) =
|
func finish(decoder: var AbiDecoder): ?!void =
|
||||||
doAssert decoder.stack.len == 1, "not all tuples were finished"
|
doAssert decoder.stack.len == 1, "not all tuples were finished"
|
||||||
doAssert decoder.last == decoder.bytes.len, "unread trailing bytes found"
|
doAssert decoder.last mod 32 == 0, "encoding invariant broken"
|
||||||
doAssert decoder.last mod 32 == 0, "encoding variant broken"
|
if decoder.last != decoder.bytes.len:
|
||||||
|
failure "unread trailing bytes found"
|
||||||
|
else:
|
||||||
|
success()
|
||||||
|
|
||||||
func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] =
|
func decode[T](decoder: var AbiDecoder, _: type seq[T]): ?!seq[T] =
|
||||||
var sequence: seq[T]
|
var sequence: seq[T]
|
||||||
|
@ -144,5 +161,5 @@ func decode(decoder: var AbiDecoder, T: type string): ?!T =
|
||||||
func decode*(_: type AbiDecoder, bytes: seq[byte], T: type): ?!T =
|
func decode*(_: type AbiDecoder, bytes: seq[byte], T: type): ?!T =
|
||||||
var decoder = AbiDecoder.init(bytes)
|
var decoder = AbiDecoder.init(bytes)
|
||||||
var value = ?decoder.decode(T)
|
var value = ?decoder.decode(T)
|
||||||
decoder.finish()
|
?decoder.finish()
|
||||||
success value
|
success value
|
||||||
|
|
|
@ -20,14 +20,31 @@ suite "ABI decoding":
|
||||||
checkDecode(uint32)
|
checkDecode(uint32)
|
||||||
checkDecode(uint64)
|
checkDecode(uint64)
|
||||||
|
|
||||||
# TODO: failure to decode when prefix not all zeroes
|
test "fails to decode when reading past end":
|
||||||
# TODO: failure when trailing bytes
|
var encoded = AbiEncoder.encode(uint8.example)
|
||||||
|
encoded.delete(encoded.len-1)
|
||||||
|
let decoded = AbiDecoder.decode(encoded, uint8)
|
||||||
|
check decoded.error.msg == "reading past end"
|
||||||
|
|
||||||
|
test "fails to decode when trailing bytes remain":
|
||||||
|
var encoded = AbiEncoder.encode(uint8.example)
|
||||||
|
encoded.add(byte.example)
|
||||||
|
let decoded = AbiDecoder.decode(encoded, uint8)
|
||||||
|
check decoded.error.msg == "unread trailing bytes found"
|
||||||
|
|
||||||
|
test "fails to decode when padding does not consist of zeroes":
|
||||||
|
var encoded = AbiEncoder.encode(uint8.example)
|
||||||
|
encoded[3] = 42'u8
|
||||||
|
let decoded = AbiDecoder.decode(encoded, uint8)
|
||||||
|
check decoded.error.msg == "invalid padding found"
|
||||||
|
|
||||||
test "decodes booleans":
|
test "decodes booleans":
|
||||||
checkDecode(false)
|
checkDecode(false)
|
||||||
checkDecode(true)
|
checkDecode(true)
|
||||||
|
|
||||||
# TODO: failure to decode when value not 0 or 1
|
test "fails to decode boolean when value is not 0 or 1":
|
||||||
|
let encoded = AbiEncoder.encode(2'u8)
|
||||||
|
check AbiDecoder.decode(encoded, bool).error.msg == "invalid boolean value"
|
||||||
|
|
||||||
test "decodes ranges":
|
test "decodes ranges":
|
||||||
type SomeRange = range[0x0000'u16..0xAAAA'u16]
|
type SomeRange = range[0x0000'u16..0xAAAA'u16]
|
||||||
|
@ -55,15 +72,11 @@ suite "ABI decoding":
|
||||||
checkDecode(array[32, byte].example)
|
checkDecode(array[32, byte].example)
|
||||||
checkDecode(array[33, byte].example)
|
checkDecode(array[33, byte].example)
|
||||||
|
|
||||||
# TODO: failure to decode when byte array of wrong length
|
|
||||||
|
|
||||||
test "decodes byte sequences":
|
test "decodes byte sequences":
|
||||||
checkDecode(@[1'u8, 2'u8, 3'u8])
|
checkDecode(@[1'u8, 2'u8, 3'u8])
|
||||||
checkDecode(@(array[32, byte].example))
|
checkDecode(@(array[32, byte].example))
|
||||||
checkDecode(@(array[33, byte].example))
|
checkDecode(@(array[33, byte].example))
|
||||||
|
|
||||||
# TODO: failure to decode when not enough bytes
|
|
||||||
|
|
||||||
test "decodes tuples":
|
test "decodes tuples":
|
||||||
let a = true
|
let a = true
|
||||||
let b = @[1'u8, 2'u8, 3'u8]
|
let b = @[1'u8, 2'u8, 3'u8]
|
||||||
|
|
Loading…
Reference in New Issue