Add a helper type used in web3 and elsewhere to denote blocks

This commit is contained in:
Zahary Karadjov 2020-11-12 20:56:31 +02:00
parent 71d6dbd1b4
commit 5dff021cbc
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
3 changed files with 91 additions and 1 deletions

View File

@ -1,5 +1,6 @@
import
stew/endians2, options, times, chronicles,
strutils,
stew/[endians2, byteutils], options, times, chronicles,
stint, nimcrypto/[keccak, hash], eth/rlp, eth/trie/[trie_defs, db]
export
@ -125,6 +126,7 @@ type
receiptRoot*: Hash256
blockNumber*: BlockNumber
# TODO: Make BlockNumber a uint64 and deprecate either this or BlockHashOrNumber
HashOrNum* = object
case isHash*: bool
of true:
@ -132,6 +134,13 @@ type
else:
number*: BlockNumber
BlockHashOrNumber* = object
case isHash*: bool
of true:
hash*: Hash256
else:
number*: uint64
BlocksRequest* = object
startBlock*: HashOrNum
maxResults*, skip*: uint
@ -301,6 +310,24 @@ proc read*(rlp: var Rlp, T: typedesc[HashOrStatus]): T {.inline.} =
raise newException(RlpTypeMismatch,
"HashOrStatus expected, but the source RLP is not a blob of right size.")
func init*(T: type BlockHashOrNumber, str: string): T
{.raises: [ValueError, Defect].} =
if str.startsWith "0x":
if str.len != sizeof(result.hash.data) * 2 + 2:
raise newException(ValueError, "Block hash has incorrect length")
result.isHash = true
hexToByteArray(str, result.hash.data)
else:
result.isHash = false
result.number = parseBiggestUInt str
func `$`*(x: BlockHashOrNumber): string =
if x.isHash:
"0x" & x.hash.data.toHex
else:
$x.number
proc append*(rlpWriter: var RlpWriter, value: HashOrStatus) {.inline.} =
if value.isHash:
rlpWriter.append(value.hash)

View File

@ -2,6 +2,9 @@ import
times, net,
json_serialization, nimcrypto/[hash, utils], eth_types
export
json_serialization
{.push raises: [SerializationError, IOError, Defect].}
proc writeValue*(w: var JsonWriter, a: MDigest) =
@ -42,3 +45,12 @@ proc writeValue*(w: var JsonWriter, value: HashOrNum) =
w.writeField("number", value.number)
w.endRecord()
proc writeValue*(w: var JsonWriter, value: BlockHashOrNumber) =
w.writeValue $value
proc readValue*(r: var JsonReader, value: var BlockHashOrNumber) =
try:
value = init(BlockHashOrNumber, r.readValue(string))
except ValueError:
r.raiseUnexpectedValue("A hex-encoded block hash or a decimal block number expected")

View File

@ -0,0 +1,51 @@
import
unittest,
nimcrypto/hash,
serialization/testing/generic_suite,
../../eth/common/[eth_types, eth_types_json_serialization]
func `==`*(lhs, rhs: BlockHashOrNumber): bool =
if lhs.isHash != rhs.isHash:
return false
if lhs.isHash:
lhs.hash == rhs.hash
else:
lhs.number == rhs.number
suite "BlockHashOrNumber":
test "construction":
expect ValueError:
var x = BlockHashOrNumber.init ""
echo "An empty string should not produce the value ", x
let x1 = BlockHashOrNumber.init "0"
check((not x1.isHash) and x1.number == 0)
let x2 = BlockHashOrNumber.init "1241328"
check((not x1.isHash) and x2.number == 1241328)
expect ValueError:
var x = BlockHashOrNumber.init "0x"
echo "An empty hash should not produce the value ", x
expect ValueError:
var x = BlockHashOrNumber.init "0xff11"
echo "A shorter hash should not produce the value ", x
expect ValueError:
var x = BlockHashOrNumber.init "0x7a64245f7f95164f6176d90bd4903dbdd3e5433d555dd1385e81787f9672c58z"
echo "An invalid hash should not produce the value ", x
expect ValueError:
var x = BlockHashOrNumber.init "0x7a64245f7f95164f6176d90bd4903dbdd3e5433d555dd1385e81787f9672c58811"
echo "A longer hash should not produce the value ", x
test "serialization":
let hash = Hash256.fromHex "0x7a64245f7f95164f6176d90bd4903dbdd3e5433d555dd1385e81787f9672c588"
Json.roundtripTest BlockHashOrNumber(isHash: true, hash: hash),
"\"0x7a64245f7f95164f6176d90bd4903dbdd3e5433d555dd1385e81787f9672c588\""
Json.roundtripTest BlockHashOrNumber(isHash: false, number: 1209231231),
"\"1209231231\""