Add JSON RPC hex strings support

This commit is contained in:
coffeepots 2018-07-27 18:02:02 +01:00 committed by zah
parent 79abeafa41
commit d4571c01dd
1 changed files with 103 additions and 0 deletions

103
nimbus/rpc/hexstrings.nim Normal file
View File

@ -0,0 +1,103 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
## This module implements the Ethereum hexadecimal string formats for JSON
## See: https://github.com/ethereum/wiki/wiki/JSON-RPC#hex-value-encoding
type
HexQuantityStr* = distinct string
HexDataStr* = distinct string
# Hex validation
template stripLeadingZeros(value: string): string =
var cidx = 0
# ignore the last character so we retain '0' on zero value
while cidx < value.len - 1 and value[cidx] == '0':
cidx.inc
value[cidx .. ^1]
proc encodeQuantity*(value: SomeUnsignedInt): string =
var hValue = value.toHex.stripLeadingZeros
result = "0x" & hValue
template hasHexHeader*(value: string): bool =
if value != "" and value[0] == '0' and value[1] in {'x', 'X'} and value.len > 2: true
else: false
template isHexChar*(c: char): bool =
if c notin {'0'..'9'} and
c notin {'a'..'f'} and
c notin {'A'..'F'}: false
else: true
proc validateHexQuantity*(value: string): bool =
if not value.hasHexHeader:
return false
# No leading zeros
if value[2] == '0': return false
for i in 2 ..< value.len:
let c = value[i]
if not c.isHexChar:
return false
return true
proc validateHexData*(value: string): bool =
if not value.hasHexHeader:
return false
# Must be even number of digits
if value.len mod 2 != 0: return false
# Leading zeros are allowed
for i in 2 ..< value.len:
let c = value[i]
if not c.isHexChar:
return false
return true
# Initialisation
proc hexQuantityStr*(value: string): HexQuantityStr =
if not value.validateHexQuantity:
raise newException(ValueError, "Invalid hex quantity format for Ethereum: " & value)
else:
result = value.HexQuantityStr
proc hexDataStr*(value: string): HexDataStr =
if not value.validateHexData:
raise newException(ValueError, "Invalid hex data format for Ethereum: " & value)
else:
result = value.HexDataStr
# Converters for use in RPC
import json
from json_rpc/rpcserver import expect
proc `%`*(value: HexQuantityStr): JsonNode =
result = %(value.string)
proc `%`*(value: HexDataStr): JsonNode =
result = %(value.string)
proc fromJson*(n: JsonNode, argName: string, result: var HexQuantityStr) =
# Note that '0x' is stripped after validation
n.kind.expect(JString, argName)
let hexStr = n.getStr()
if not hexStr.validateHexQuantity:
raise newException(ValueError, "Parameter \"" & argName & "\" value is not valid as an Ethereum hex quantity \"" & hexStr & "\"")
result = hexStr[2..hexStr.high].hexQuantityStr
proc fromJson*(n: JsonNode, argName: string, result: var HexDataStr) =
# Note that '0x' is stripped after validation
n.kind.expect(JString, argName)
let hexStr = n.getStr()
if not hexStr.validateHexData:
raise newException(ValueError, "Parameter \"" & argName & "\" value is not valid as a Ethereum data \"" & hexStr & "\"")
result = hexStr[2..hexStr.high].hexDataStr