Simplify encoding of tuples

This commit is contained in:
Mark Spanbroek 2021-12-01 10:58:23 +01:00
parent 766260fd88
commit 243b9a12e9
4 changed files with 30 additions and 119 deletions

View File

@ -32,13 +32,7 @@ AbiEncoder.encode([1'u8, 2'u8, 3'u8])
AbiEncoder.encode(@[1'u8, 2'u8, 3'u8]) AbiEncoder.encode(@[1'u8, 2'u8, 3'u8])
# encode tuples # encode tuples
var encoder = AbiEncoder.init() AbiEncoder.encode( (42'u8, @[1'u8, 2'u8, 3'u8], true) )
encoder.startTuple()
encoder.write(42'u8)
encoder.write(@[1'u8, 2'u8, 3'u8])
encoder.write(true)
encoder.finishTuple()
encoder.finish()
``` ```
[1]: https://docs.soliditylang.org/en/latest/abi-spec.html [1]: https://docs.soliditylang.org/en/latest/abi-spec.html

View File

@ -54,7 +54,7 @@ func postpone(encoder: var AbiEncoder, bytes: seq[byte]) =
func setDynamic(encoder: var AbiEncoder) = func setDynamic(encoder: var AbiEncoder) =
encoder.stack[^1].dynamic = true encoder.stack[^1].dynamic = true
func startTuple*(encoder: var AbiEncoder) = func startTuple(encoder: var AbiEncoder) =
encoder.stack.add(Tuple()) encoder.stack.add(Tuple())
func encode(encoder: var AbiEncoder, tupl: Tuple) = func encode(encoder: var AbiEncoder, tupl: Tuple) =
@ -64,7 +64,7 @@ func encode(encoder: var AbiEncoder, tupl: Tuple) =
else: else:
encoder.append(tupl.finish()) encoder.append(tupl.finish())
func finishTuple*(encoder: var AbiEncoder) = func finishTuple(encoder: var AbiEncoder) =
encoder.encode(encoder.stack.pop()) encoder.encode(encoder.stack.pop())
func pad(encoder: var AbiEncoder, len: int) = func pad(encoder: var AbiEncoder, len: int) =
@ -114,6 +114,12 @@ func encode[T](encoder: var AbiEncoder, value: seq[T]) =
func encode(encoder: var AbiEncoder, value: string) = func encode(encoder: var AbiEncoder, value: string) =
encoder.encode(value.toBytes) encoder.encode(value.toBytes)
func encode(encoder: var AbiEncoder, tupl: tuple) =
encoder.startTuple()
for element in tupl.fields:
encoder.write(element)
encoder.finishTuple()
func write*[T](encoder: var AbiEncoder, value: T) = func write*[T](encoder: var AbiEncoder, value: T) =
var writer = AbiEncoder.init() var writer = AbiEncoder.init()
writer.encode(value) writer.encode(value)

View File

@ -68,15 +68,7 @@ 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) )
var encoder= AbiEncoder.init()
encoder.startTuple()
encoder.write(a)
encoder.write(b)
encoder.write(c)
encoder.write(d)
encoder.finishTuple()
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=true) decoder.startTuple(dynamic=true)
@ -93,17 +85,7 @@ suite "ABI decoding":
let c = 0xAABBCCDD'u32 let c = 0xAABBCCDD'u32
let d = @[4'u8, 5'u8, 6'u8] let d = @[4'u8, 5'u8, 6'u8]
var encoder= AbiEncoder.init() let encoding = AbiEncoder.encode( (a, b, (c, d)) )
encoder.startTuple()
encoder.write(a)
encoder.write(b)
encoder.startTuple()
encoder.write(c)
encoder.write(d)
encoder.finishTuple()
encoder.finishTuple()
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=true) decoder.startTuple(dynamic=true)
check decoder.read(bool) == a check decoder.read(bool) == a
@ -118,49 +100,35 @@ suite "ABI decoding":
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
var encoder = AbiEncoder.init() let encoding = AbiEncoder.encode( ((a,), b) )
encoder.startTuple()
encoder.write(a)
encoder.finishTuple()
encoder.write(b)
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=true) decoder.startTuple(dynamic=true)
decoder.startTuple(dynamic=true)
check decoder.read(seq[byte]) == a check decoder.read(seq[byte]) == a
decoder.finishTuple() decoder.finishTuple()
check decoder.read(uint32) == b check decoder.read(uint32) == b
decoder.finishTuple()
decoder.finish() 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
var encoder = AbiEncoder.init() let encoding = AbiEncoder.encode( ((a,), b) )
encoder.startTuple()
encoder.write(a)
encoder.finishTuple()
encoder.write(b)
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=false) decoder.startTuple(dynamic=false)
decoder.startTuple(dynamic=false)
check decoder.read(uint16) == a check decoder.read(uint16) == a
decoder.finishTuple() decoder.finishTuple()
check decoder.read(uint32) == b check decoder.read(uint32) == b
decoder.finishTuple()
decoder.finish() 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,)) )
var encoder= AbiEncoder.init()
encoder.startTuple()
encoder.write(a)
encoder.startTuple()
encoder.write(b)
encoder.finishTuple()
encoder.finishTuple()
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=true) decoder.startTuple(dynamic=true)
@ -172,12 +140,7 @@ suite "ABI decoding":
decoder.finish() decoder.finish()
test "reads empty tuples": test "reads empty tuples":
var encoder = AbiEncoder.init() let encoding = AbiEncoder.encode( ((),) )
encoder.startTuple()
encoder.startTuple()
encoder.finishTuple()
encoder.finishTuple()
let encoding = encoder.finish()
var decoder = AbiDecoder.init(encoding) var decoder = AbiDecoder.init(encoding)
decoder.startTuple(dynamic=false) decoder.startTuple(dynamic=false)

View File

@ -68,14 +68,7 @@ suite "ABI encoding":
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]
var encoder= AbiEncoder.init() check AbiEncoder.encode( (a, b, c, d) ) ==
encoder.startTuple()
encoder.write(a)
encoder.write(b)
encoder.write(c)
encoder.write(d)
encoder.finishTuple()
check encoder.finish() ==
AbiEncoder.encode(a) & AbiEncoder.encode(a) &
AbiEncoder.encode(4 * 32'u8) & # offset in tuple AbiEncoder.encode(4 * 32'u8) & # offset in tuple
AbiEncoder.encode(c) & AbiEncoder.encode(c) &
@ -88,16 +81,7 @@ suite "ABI encoding":
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]
var encoder= AbiEncoder.init() check AbiEncoder.encode( (a, b, (c, d)) ) ==
encoder.startTuple()
encoder.write(a)
encoder.write(b)
encoder.startTuple()
encoder.write(c)
encoder.write(d)
encoder.finishTuple()
encoder.finishTuple()
check encoder.finish() ==
AbiEncoder.encode(a) & AbiEncoder.encode(a) &
AbiEncoder.encode(3 * 32'u8) & # offset of b in outer tuple AbiEncoder.encode(3 * 32'u8) & # offset of b in outer tuple
AbiEncoder.encode(5 * 32'u8) & # offset of inner tuple in outer tuple AbiEncoder.encode(5 * 32'u8) & # offset of inner tuple in outer tuple
@ -106,65 +90,29 @@ suite "ABI encoding":
AbiEncoder.encode(2 * 32'u8) & # offset of d in inner tuple AbiEncoder.encode(2 * 32'u8) & # offset of d in inner tuple
AbiEncoder.encode(d) AbiEncoder.encode(d)
test "encodes element after dynamic tuple":
let a = @[1'u8, 2'u8, 3'u8]
let b = 0xAABBCCDD'u32
var encoder= AbiEncoder.init()
encoder.startTuple()
encoder.write(a)
encoder.finishTuple()
encoder.write(b)
check encoder.finish() ==
AbiEncoder.encode(1 * 32'u8) & # offset of a in tuple
AbiEncoder.encode(a) &
AbiEncoder.encode(b)
test "encodes arrays": test "encodes arrays":
let element1 = seq[byte].example let a, b = seq[byte].example
let element2 = seq[byte].example check AbiEncoder.encode([a, b]) == AbiEncoder.encode( (a,b) )
var expected= AbiEncoder.init()
expected.startTuple()
expected.write(element1)
expected.write(element2)
expected.finishTuple()
check AbiEncoder.encode([element1, element2]) == expected.finish()
test "encodes sequences": test "encodes sequences":
let element1 = seq[byte].example let a, b = seq[byte].example
let element2 = seq[byte].example check AbiEncoder.encode(@[a, b]) ==
var expected= AbiEncoder.init() AbiEncoder.encode(2'u64) &
expected.write(2'u8) AbiEncoder.encode( (a, b) )
expected.startTuple()
expected.write(element1)
expected.write(element2)
expected.finishTuple()
check AbiEncoder.encode(@[element1, element2]) == expected.finish()
test "encodes sequence as dynamic element": test "encodes sequence as dynamic element":
let s = @[42.u256, 43.u256] let s = @[42.u256, 43.u256]
var encoder= AbiEncoder.init() check AbiEncoder.encode( (s,) ) ==
encoder.startTuple()
encoder.write(s)
encoder.finishTuple()
check encoder.finish() ==
AbiEncoder.encode(32'u8) & # offset in tuple AbiEncoder.encode(32'u8) & # offset in tuple
AbiEncoder.encode(s) AbiEncoder.encode(s)
test "encodes array of static elements as static element": test "encodes array of static elements as static element":
let a = [[42'u8], [43'u8]] let a = [[42'u8], [43'u8]]
var encoder= AbiEncoder.init() check AbiEncoder.encode( (a,) ) == AbiEncoder.encode(a)
encoder.startTuple()
encoder.write(a)
encoder.finishTuple()
check encoder.finish() == AbiEncoder.encode(a)
test "encodes array of dynamic elements as dynamic element": test "encodes array of dynamic elements as dynamic element":
let a = [@[42'u8], @[43'u8]] let a = [@[42'u8], @[43'u8]]
var encoder= AbiEncoder.init() check AbiEncoder.encode( (a,) ) ==
encoder.startTuple()
encoder.write(a)
encoder.finishTuple()
check encoder.finish() ==
AbiEncoder.encode(32'u8) & # offset in tuple AbiEncoder.encode(32'u8) & # offset in tuple
AbiEncoder.encode(a) AbiEncoder.encode(a)