From 2aa8685eb5728c7b09c01ea496a265d1c054be44 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Wed, 1 Dec 2021 11:40:12 +0100 Subject: [PATCH] Simplify decoding of tuples --- contractabi/decoding.nim | 11 ++++- tests/contractabi/testDecoding.nim | 66 +++--------------------------- 2 files changed, 15 insertions(+), 62 deletions(-) diff --git a/contractabi/decoding.nim b/contractabi/decoding.nim index cdf1bd3..36fb237 100644 --- a/contractabi/decoding.nim +++ b/contractabi/decoding.nim @@ -84,7 +84,7 @@ func decode*(decoder: var AbiDecoder, T: type seq[byte]): T = let len = decoder.read(uint64).int decoder.read(len, padRight) -func startTuple*(decoder: var AbiDecoder, dynamic: bool) = +func startTuple(decoder: var AbiDecoder, dynamic: bool) = var start: int if decoder.currentTuple.dynamic and dynamic: start = decoder.readOffset() @@ -92,12 +92,19 @@ func startTuple*(decoder: var AbiDecoder, dynamic: bool) = start = decoder.index decoder.stack.add(Tuple.init(start, dynamic)) -func finishTuple*(decoder: var AbiDecoder) = +func finishTuple(decoder: var AbiDecoder) = doAssert decoder.stack.len > 1, "unable to finish a tuple that hasn't started" let tupl = decoder.stack.pop() if not tupl.dynamic: decoder.index = tupl.index +func decode*(decoder: var AbiDecoder, T: type tuple): T = + const dynamic = AbiEncoder.isDynamic(typeof(result)) + decoder.startTuple(dynamic) + for element in result.fields: + element = decoder.read(typeof(element)) + decoder.finishTuple() + func finish*(decoder: var AbiDecoder) = doAssert decoder.stack.len == 1, "not all tuples were finished" doAssert decoder.last == decoder.bytes.len, "unread trailing bytes found" diff --git a/tests/contractabi/testDecoding.nim b/tests/contractabi/testDecoding.nim index d6e44d3..23e1025 100644 --- a/tests/contractabi/testDecoding.nim +++ b/tests/contractabi/testDecoding.nim @@ -68,86 +68,32 @@ suite "ABI decoding": let b = @[1'u8, 2'u8, 3'u8] let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - let encoding = AbiEncoder.encode( (a, b, c, d) ) - - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=true) - check decoder.read(bool) == a - check decoder.read(seq[byte]) == b - check decoder.read(uint32) == c - check decoder.read(seq[byte]) == d - decoder.finishTuple() - decoder.finish() + checkDecode( (a, b, c, d) ) test "decodes nested tuples": let a = true let b = @[1'u8, 2'u8, 3'u8] let c = 0xAABBCCDD'u32 let d = @[4'u8, 5'u8, 6'u8] - - let encoding = AbiEncoder.encode( (a, b, (c, d)) ) - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=true) - check decoder.read(bool) == a - check decoder.read(seq[byte]) == b - decoder.startTuple(dynamic=true) - check decoder.read(uint32) == c - check decoder.read(seq[byte]) == d - decoder.finishTuple() - decoder.finishTuple() - decoder.finish() + checkDecode( (a, b, (c, d)) ) test "reads elements after dynamic tuple": let a = @[1'u8, 2'u8, 3'u8] let b = 0xAABBCCDD'u32 - let encoding = AbiEncoder.encode( ((a,), b) ) - - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=true) - decoder.startTuple(dynamic=true) - check decoder.read(seq[byte]) == a - decoder.finishTuple() - check decoder.read(uint32) == b - decoder.finishTuple() - decoder.finish() + checkDecode( ((a,), b) ) test "reads elements after static tuple": let a = 0x123'u16 let b = 0xAABBCCDD'u32 - let encoding = AbiEncoder.encode( ((a,), b) ) - - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=false) - decoder.startTuple(dynamic=false) - check decoder.read(uint16) == a - decoder.finishTuple() - check decoder.read(uint32) == b - decoder.finishTuple() - decoder.finish() + checkDecode( ((a,), b) ) test "reads static tuple inside dynamic tuple": let a = @[1'u8, 2'u8, 3'u8] let b = 0xAABBCCDD'u32 - let encoding = AbiEncoder.encode( (a, (b,)) ) - - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=true) - check decoder.read(seq[byte]) == a - decoder.startTuple(dynamic=false) - check decoder.read(uint32) == b - decoder.finishTuple() - decoder.finishTuple() - decoder.finish() + checkDecode( (a, (b,)) ) test "reads empty tuples": - let encoding = AbiEncoder.encode( ((),) ) - - var decoder = AbiDecoder.init(encoding) - decoder.startTuple(dynamic=false) - decoder.startTuple(dynamic=false) - decoder.finishTuple() - decoder.finishTuple() - decoder.finish() + checkDecode( ((),) ) test "decodes sequences": checkDecode(@[seq[byte].example, seq[byte].example])