More complete DynamicBytes implementation

This commit is contained in:
Zahary Karadjov 2021-10-10 13:20:18 +02:00
parent 9a0f1425c1
commit 74ae794993
3 changed files with 40 additions and 23 deletions

View File

@ -37,7 +37,7 @@ proc fromJson*[N](n: JsonNode, argName: string, result: var FixedBytes[N]) {.inl
# expects base 16 string, starting with "0x" # expects base 16 string, starting with "0x"
bytesFromJson(n, argName, array[N, byte](result)) bytesFromJson(n, argName, array[N, byte](result))
proc fromJson*[N](n: JsonNode, argName: string, result: var DynamicBytes[N]) {.inline.} = proc fromJson*(n: JsonNode, argName: string, result: var DynamicBytes) {.inline.} =
n.kind.expect(JString, argName) n.kind.expect(JString, argName)
result = fromHex(type result, n.getStr()) result = fromHex(type result, n.getStr())
@ -61,7 +61,7 @@ proc `%`*(v: Quantity): JsonNode =
proc `%`*[N](v: FixedBytes[N]): JsonNode = proc `%`*[N](v: FixedBytes[N]): JsonNode =
result = %("0x" & array[N, byte](v).toHex) result = %("0x" & array[N, byte](v).toHex)
proc `%`*[N](v: DynamicBytes[N]): JsonNode = proc `%`*(v: DynamicBytes): JsonNode =
result = %("0x" & toHex(v)) result = %("0x" & toHex(v))
proc `%`*(v: Address): JsonNode = proc `%`*(v: Address): JsonNode =
@ -75,7 +75,7 @@ proc writeHexValue(w: JsonWriter, v: openarray[byte]) =
w.stream.writeHex v w.stream.writeHex v
w.stream.write "\"" w.stream.write "\""
proc writeValue*[N](w: var JsonWriter, v: DynamicBytes[N]) = proc writeValue*(w: var JsonWriter, v: DynamicBytes) =
writeHexValue w, distinctBase(v) writeHexValue w, distinctBase(v)
proc writeValue*[N](w: var JsonWriter, v: FixedBytes[N]) = proc writeValue*[N](w: var JsonWriter, v: FixedBytes[N]) =
@ -87,7 +87,7 @@ proc writeValue*(w: var JsonWriter, v: Address) =
proc writeValue*(w: var JsonWriter, v: TypedTransaction) = proc writeValue*(w: var JsonWriter, v: TypedTransaction) =
writeHexValue w, distinctBase(v) writeHexValue w, distinctBase(v)
proc readValue*[N](r: var JsonReader, T: type DynamicBytes[N]): T = proc readValue*(r: var JsonReader, T: type DynamicBytes): T =
fromHex(T, r.readValue(string)) fromHex(T, r.readValue(string))
proc readValue*[N](r: var JsonReader, T: type FixedBytes[N]): T = proc readValue*[N](r: var JsonReader, T: type FixedBytes[N]): T =
@ -108,7 +108,7 @@ proc `$`*(v: Address): string {.inline.} =
proc `$`*(v: TypedTransaction): string {.inline.} = proc `$`*(v: TypedTransaction): string {.inline.} =
"0x" & distinctBase(v).toHex "0x" & distinctBase(v).toHex
proc `$`*[N](v: DynamicBytes[N]): string {.inline.} = proc `$`*(v: DynamicBytes): string {.inline.} =
"0x" & toHex(v) "0x" & toHex(v)
proc `%`*(x: EthSend): JsonNode = proc `%`*(x: EthSend): JsonNode =

View File

@ -62,10 +62,13 @@ func encodeDynamic(v: openarray[byte]): EncodeResult =
result.data &= y.toHex.toLower result.data &= y.toHex.toLower
result.data &= "00".repeat(v.len mod 32) result.data &= "00".repeat(v.len mod 32)
func encode*[N](x: DynamicBytes[N]): EncodeResult {.inline.} = func encode*(x: DynamicBytes): EncodeResult {.inline.} =
encodeDynamic(distinctBase(x)) encodeDynamic(distinctBase x)
func decodeDynamic(input: string, offset: int, to: var openarray[byte]): int = func decodeDynamic(input: string,
offset: int,
minLen, maxLen: int,
to: var openarray[byte]): int =
var dataOffset, dataLen: UInt256 var dataOffset, dataLen: UInt256
result = decode(input, offset, dataOffset) result = decode(input, offset, dataOffset)
discard decode(input, dataOffset.truncate(int) * 2, dataLen) discard decode(input, dataOffset.truncate(int) * 2, dataLen)
@ -74,9 +77,8 @@ func decodeDynamic(input: string, offset: int, to: var openarray[byte]): int =
let actualDataOffset = (dataOffset.truncate(int) + 32) * 2 let actualDataOffset = (dataOffset.truncate(int) + 32) * 2
hexToByteArray(input[actualDataOffset .. actualDataOffset + meaningfulLen - 1], to) hexToByteArray(input[actualDataOffset .. actualDataOffset + meaningfulLen - 1], to)
func decode*[N](input: string, offset: int, to: var DynamicBytes[N]): int {.inline.} = func decode*(input: string, offset: int, to: var DynamicBytes): int {.inline.} =
{.fatal: "decodeDynamic is not implemented properly".} decodeDynamic(input, offset, to.minLen, to.maxLen, distinctBase(to))
decodeDynamic(input, offset, distinctBase(to))
macro makeTypeEnum(): untyped = macro makeTypeEnum(): untyped =
## This macro creates all the various types of Solidity contracts and maps ## This macro creates all the various types of Solidity contracts and maps

View File

@ -9,7 +9,9 @@ type
highestBlock*: int highestBlock*: int
FixedBytes*[N: static[int]] = distinct array[N, byte] FixedBytes*[N: static[int]] = distinct array[N, byte]
DynamicBytes*[MaxLen: static[int]] = distinct seq[byte] DynamicBytes*[
minLen: static[int] = 0,
maxLen: static[int] = high(int)] = distinct seq[byte]
Address* = distinct array[20, byte] Address* = distinct array[20, byte]
TxHash* = FixedBytes[32] TxHash* = FixedBytes[32]
@ -210,7 +212,7 @@ type
gasLimit*: Quantity gasLimit*: Quantity
gasUsed*: Quantity gasUsed*: Quantity
timestamp*: Quantity timestamp*: Quantity
extraData*: DynamicBytes[32] extraData*: DynamicBytes[32, 32]
baseFeePerGas*: UInt256 baseFeePerGas*: UInt256
blockHash*: BlockHash blockHash*: BlockHash
transactions*: seq[TypedTransaction] transactions*: seq[TypedTransaction]
@ -218,7 +220,7 @@ type
template `==`*[N](a, b: FixedBytes[N]): bool = template `==`*[N](a, b: FixedBytes[N]): bool =
distinctBase(a) == distinctBase(b) distinctBase(a) == distinctBase(b)
template `==`*[N](a, b: DynamicBytes[N]): bool = template `==`*[minLen, maxLen](a, b: DynamicBytes[minLen, maxLen]): bool =
distinctBase(a) == distinctBase(b) distinctBase(a) == distinctBase(b)
proc `==`*(a, b: Address): bool {.inline.} = proc `==`*(a, b: Address): bool {.inline.} =
@ -239,7 +241,7 @@ func hash*[N](bytes: FixedBytes[N]): Hash =
template toHex*[N](x: FixedBytes[N]): string = template toHex*[N](x: FixedBytes[N]): string =
toHex(distinctBase x) toHex(distinctBase x)
template toHex*[N](x: DynamicBytes[N]): string = template toHex*[minLen, maxLen](x: DynamicBytes[minLen, maxLen]): string =
toHex(distinctBase x) toHex(distinctBase x)
template toHex*(x: Address): string = template toHex*(x: Address): string =
@ -248,14 +250,6 @@ template toHex*(x: Address): string =
template fromHex*(T: type Address, hexStr: string): T = template fromHex*(T: type Address, hexStr: string): T =
T fromHex(distinctBase(T), hexStr) T fromHex(distinctBase(T), hexStr)
func fromHex*[N](T: type DynamicBytes[N], hexStr: string): T =
if hexStr.len > N * 2:
raise newException(ValueError, "hex input too large")
T hexToSeqByte(hexStr)
template fromHex*[N](T: type FixedBytes[N], hexStr: string): T =
T fromHex(distinctBase(T), hexStr)
template skip0xPrefix(hexStr: string): int = template skip0xPrefix(hexStr: string): int =
## Returns the index of the first meaningful char in `hexStr` by skipping ## Returns the index of the first meaningful char in `hexStr` by skipping
## "0x" prefix ## "0x" prefix
@ -269,3 +263,24 @@ proc strip0xPrefix*(s: string): string =
else: else:
s s
func fromHex*[minLen](T: type DynamicBytes[minLen, maxLen], hexStr: string): T =
let prefixLen = skip0xPrefix(hexStr)
let hexDataLen = hexStr.len - prefixLen
if hexDataLen < minLen * 2:
raise newException(ValueError, "hex input too small")
if hexDataLen > maxLen * 2:
raise newException(ValueError, "hex input too large")
T hexToSeqByte(hexStr)
template fromHex*[N](T: type FixedBytes[N], hexStr: string): T =
T fromHex(distinctBase(T), hexStr)
proc toArray*[N](data: DynamicBytes[N, N]): array[N, byte] =
copyMem(addr result[0], unsafeAddr distinctBase(data)[0], N)
template bytes*(data: DynamicBytes): seq[byte] =
distinctBase data