From 74ae79499386e819262815c17587d319b9361aad Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 10 Oct 2021 13:20:18 +0200 Subject: [PATCH] More complete DynamicBytes implementation --- web3/conversions.nim | 10 +++++----- web3/encoding.nim | 14 ++++++++------ web3/ethtypes.nim | 39 +++++++++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/web3/conversions.nim b/web3/conversions.nim index f55ecea..80481d8 100644 --- a/web3/conversions.nim +++ b/web3/conversions.nim @@ -37,7 +37,7 @@ proc fromJson*[N](n: JsonNode, argName: string, result: var FixedBytes[N]) {.inl # expects base 16 string, starting with "0x" 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) result = fromHex(type result, n.getStr()) @@ -61,7 +61,7 @@ proc `%`*(v: Quantity): JsonNode = proc `%`*[N](v: FixedBytes[N]): JsonNode = result = %("0x" & array[N, byte](v).toHex) -proc `%`*[N](v: DynamicBytes[N]): JsonNode = +proc `%`*(v: DynamicBytes): JsonNode = result = %("0x" & toHex(v)) proc `%`*(v: Address): JsonNode = @@ -75,7 +75,7 @@ proc writeHexValue(w: JsonWriter, v: openarray[byte]) = w.stream.writeHex v w.stream.write "\"" -proc writeValue*[N](w: var JsonWriter, v: DynamicBytes[N]) = +proc writeValue*(w: var JsonWriter, v: DynamicBytes) = writeHexValue w, distinctBase(v) 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) = 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)) 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.} = "0x" & distinctBase(v).toHex -proc `$`*[N](v: DynamicBytes[N]): string {.inline.} = +proc `$`*(v: DynamicBytes): string {.inline.} = "0x" & toHex(v) proc `%`*(x: EthSend): JsonNode = diff --git a/web3/encoding.nim b/web3/encoding.nim index cd16f77..aa13143 100644 --- a/web3/encoding.nim +++ b/web3/encoding.nim @@ -62,10 +62,13 @@ func encodeDynamic(v: openarray[byte]): EncodeResult = result.data &= y.toHex.toLower result.data &= "00".repeat(v.len mod 32) -func encode*[N](x: DynamicBytes[N]): EncodeResult {.inline.} = - encodeDynamic(distinctBase(x)) +func encode*(x: DynamicBytes): EncodeResult {.inline.} = + 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 result = decode(input, offset, dataOffset) 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 hexToByteArray(input[actualDataOffset .. actualDataOffset + meaningfulLen - 1], to) -func decode*[N](input: string, offset: int, to: var DynamicBytes[N]): int {.inline.} = - {.fatal: "decodeDynamic is not implemented properly".} - decodeDynamic(input, offset, distinctBase(to)) +func decode*(input: string, offset: int, to: var DynamicBytes): int {.inline.} = + decodeDynamic(input, offset, to.minLen, to.maxLen, distinctBase(to)) macro makeTypeEnum(): untyped = ## This macro creates all the various types of Solidity contracts and maps diff --git a/web3/ethtypes.nim b/web3/ethtypes.nim index ceea55f..1c9cc36 100644 --- a/web3/ethtypes.nim +++ b/web3/ethtypes.nim @@ -9,7 +9,9 @@ type highestBlock*: int 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] TxHash* = FixedBytes[32] @@ -210,7 +212,7 @@ type gasLimit*: Quantity gasUsed*: Quantity timestamp*: Quantity - extraData*: DynamicBytes[32] + extraData*: DynamicBytes[32, 32] baseFeePerGas*: UInt256 blockHash*: BlockHash transactions*: seq[TypedTransaction] @@ -218,7 +220,7 @@ type template `==`*[N](a, b: FixedBytes[N]): bool = distinctBase(a) == distinctBase(b) -template `==`*[N](a, b: DynamicBytes[N]): bool = +template `==`*[minLen, maxLen](a, b: DynamicBytes[minLen, maxLen]): bool = distinctBase(a) == distinctBase(b) proc `==`*(a, b: Address): bool {.inline.} = @@ -239,7 +241,7 @@ func hash*[N](bytes: FixedBytes[N]): Hash = template toHex*[N](x: FixedBytes[N]): string = toHex(distinctBase x) -template toHex*[N](x: DynamicBytes[N]): string = +template toHex*[minLen, maxLen](x: DynamicBytes[minLen, maxLen]): string = toHex(distinctBase x) template toHex*(x: Address): string = @@ -248,14 +250,6 @@ template toHex*(x: Address): string = template fromHex*(T: type Address, hexStr: string): T = 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 = ## Returns the index of the first meaningful char in `hexStr` by skipping ## "0x" prefix @@ -269,3 +263,24 @@ proc strip0xPrefix*(s: string): string = else: 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 +