Simplify encoding of tuples
This commit is contained in:
parent
766260fd88
commit
243b9a12e9
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue