Simplify decoding of tuples

This commit is contained in:
Mark Spanbroek 2021-12-01 11:40:12 +01:00
parent ead71d7f87
commit 2aa8685eb5
2 changed files with 15 additions and 62 deletions

View File

@ -84,7 +84,7 @@ func decode*(decoder: var AbiDecoder, T: type seq[byte]): T =
let len = decoder.read(uint64).int let len = decoder.read(uint64).int
decoder.read(len, padRight) decoder.read(len, padRight)
func startTuple*(decoder: var AbiDecoder, dynamic: bool) = func startTuple(decoder: var AbiDecoder, dynamic: bool) =
var start: int var start: int
if decoder.currentTuple.dynamic and dynamic: if decoder.currentTuple.dynamic and dynamic:
start = decoder.readOffset() start = decoder.readOffset()
@ -92,12 +92,19 @@ func startTuple*(decoder: var AbiDecoder, dynamic: bool) =
start = decoder.index start = decoder.index
decoder.stack.add(Tuple.init(start, dynamic)) 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" doAssert decoder.stack.len > 1, "unable to finish a tuple that hasn't started"
let tupl = decoder.stack.pop() let tupl = decoder.stack.pop()
if not tupl.dynamic: if not tupl.dynamic:
decoder.index = tupl.index 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) = func finish*(decoder: var AbiDecoder) =
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 == decoder.bytes.len, "unread trailing bytes found"

View File

@ -68,86 +68,32 @@ suite "ABI decoding":
let b = @[1'u8, 2'u8, 3'u8] let b = @[1'u8, 2'u8, 3'u8]
let c = 0xAABBCCDD'u32 let c = 0xAABBCCDD'u32
let d = @[4'u8, 5'u8, 6'u8] let d = @[4'u8, 5'u8, 6'u8]
let encoding = AbiEncoder.encode( (a, b, c, d) ) checkDecode( (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()
test "decodes nested tuples": test "decodes nested tuples":
let a = true let a = true
let b = @[1'u8, 2'u8, 3'u8] let b = @[1'u8, 2'u8, 3'u8]
let c = 0xAABBCCDD'u32 let c = 0xAABBCCDD'u32
let d = @[4'u8, 5'u8, 6'u8] let d = @[4'u8, 5'u8, 6'u8]
checkDecode( (a, b, (c, d)) )
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()
test "reads elements after dynamic tuple": test "reads elements after dynamic tuple":
let a = @[1'u8, 2'u8, 3'u8] let a = @[1'u8, 2'u8, 3'u8]
let b = 0xAABBCCDD'u32 let b = 0xAABBCCDD'u32
let encoding = AbiEncoder.encode( ((a,), b) ) checkDecode( ((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()
test "reads elements after static tuple": test "reads elements after static tuple":
let a = 0x123'u16 let a = 0x123'u16
let b = 0xAABBCCDD'u32 let b = 0xAABBCCDD'u32
let encoding = AbiEncoder.encode( ((a,), b) ) checkDecode( ((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()
test "reads static tuple inside dynamic tuple": test "reads static tuple inside dynamic tuple":
let a = @[1'u8, 2'u8, 3'u8] let a = @[1'u8, 2'u8, 3'u8]
let b = 0xAABBCCDD'u32 let b = 0xAABBCCDD'u32
let encoding = AbiEncoder.encode( (a, (b,)) ) checkDecode( (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()
test "reads empty tuples": test "reads empty tuples":
let encoding = AbiEncoder.encode( ((),) ) checkDecode( ((),) )
var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=false)
decoder.startTuple(dynamic=false)
decoder.finishTuple()
decoder.finishTuple()
decoder.finish()
test "decodes sequences": test "decodes sequences":
checkDecode(@[seq[byte].example, seq[byte].example]) checkDecode(@[seq[byte].example, seq[byte].example])