2021-03-26 06:52:01 +00:00
|
|
|
# beacon_chain
|
|
|
|
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
2021-03-26 14:11:06 +00:00
|
|
|
# The serializations in this file are approximations of
|
|
|
|
# https://ethereum.github.io/eth2.0-APIs/#/ but where written before the standard
|
|
|
|
# had materialized - they've now made it out to releases which means the easiest
|
|
|
|
# thing to do is to maintain them as-is, even if there are mismatches. In
|
|
|
|
# particular, numbers are serialized as strings in the eth2 API - here, they
|
|
|
|
# use numbers instead.
|
|
|
|
#
|
|
|
|
# Using numbers creates problems - uint64 which often appears in eth2 can't
|
|
|
|
# portably be represented since many json parsers balk at anything >2^53 and
|
|
|
|
# start losing precision. The other issue is the json parser in nim - it can't
|
|
|
|
# handle numbers >2^63, either crashing or giving wrong results:
|
|
|
|
# https://github.com/status-im/nimbus-eth2/issues/2430
|
|
|
|
|
2020-05-22 17:04:52 +00:00
|
|
|
import
|
|
|
|
# Standard library
|
2022-01-06 07:38:40 +00:00
|
|
|
std/[typetraits],
|
2020-06-03 13:52:02 +00:00
|
|
|
|
2020-05-22 17:04:52 +00:00
|
|
|
# Nimble packages
|
2021-03-05 13:12:00 +00:00
|
|
|
stew/byteutils,
|
2020-05-22 17:04:52 +00:00
|
|
|
json_rpc/jsonmarshal,
|
2021-10-21 20:27:06 +00:00
|
|
|
ssz_serialization/types,
|
2020-05-22 17:04:52 +00:00
|
|
|
|
|
|
|
# Local modules
|
2021-08-12 13:08:20 +00:00
|
|
|
../datatypes/base
|
2020-10-28 18:51:38 +00:00
|
|
|
|
2021-08-12 13:08:20 +00:00
|
|
|
export jsonmarshal, base
|
2021-03-26 14:11:06 +00:00
|
|
|
|
2020-10-28 18:51:38 +00:00
|
|
|
proc toJsonHex(data: openArray[byte]): string =
|
|
|
|
# Per the eth2 API spec, hex arrays are printed with leading 0x
|
|
|
|
"0x" & toHex(data)
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var ValidatorPubKey) {.raises: [Defect, ValueError].} =
|
2020-06-29 17:30:19 +00:00
|
|
|
n.kind.expect(JString, argName)
|
Speed up altair block processing 2x (#3115)
* Speed up altair block processing >2x
Like #3089, this PR drastially speeds up historical REST queries and
other long state replays.
* cache sync committee validator indices
* use ~80mb less memory for validator pubkey mappings
* batch-verify sync aggregate signature (fixes #2985)
* document sync committee hack with head block vs sync message block
* add batch signature verification failure tests
Before:
```
../env.sh nim c -d:release -r ncli_db --db:mainnet_0/db bench --start-slot:-1000
All time are ms
Average, StdDev, Min, Max, Samples, Test
Validation is turned off meaning that no BLS operations are performed
5830.675, 0.000, 5830.675, 5830.675, 1, Initialize DB
0.481, 1.878, 0.215, 59.167, 981, Load block from database
8422.566, 0.000, 8422.566, 8422.566, 1, Load state from database
6.996, 1.678, 0.042, 14.385, 969, Advance slot, non-epoch
93.217, 8.318, 84.192, 122.209, 32, Advance slot, epoch
20.513, 23.665, 11.510, 201.561, 981, Apply block, no slot processing
0.000, 0.000, 0.000, 0.000, 0, Database load
0.000, 0.000, 0.000, 0.000, 0, Database store
```
After:
```
7081.422, 0.000, 7081.422, 7081.422, 1, Initialize DB
0.553, 2.122, 0.175, 66.692, 981, Load block from database
5439.446, 0.000, 5439.446, 5439.446, 1, Load state from database
6.829, 1.575, 0.043, 12.156, 969, Advance slot, non-epoch
94.716, 2.749, 88.395, 100.026, 32, Advance slot, epoch
11.636, 23.766, 4.889, 205.250, 981, Apply block, no slot processing
0.000, 0.000, 0.000, 0.000, 0, Database load
0.000, 0.000, 0.000, 0.000, 0, Database store
```
* add comment
2021-11-24 12:43:50 +00:00
|
|
|
result = ValidatorPubKey.fromHex(n.getStr()).tryGet()
|
2020-05-22 17:04:52 +00:00
|
|
|
|
|
|
|
proc `%`*(pubkey: ValidatorPubKey): JsonNode =
|
2020-10-28 18:51:38 +00:00
|
|
|
newJString(toJsonHex(toRaw(pubkey)))
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var List) {.raises: [Defect, ValueError].} =
|
2020-05-22 17:04:52 +00:00
|
|
|
fromJson(n, argName, asSeq result)
|
|
|
|
|
|
|
|
proc `%`*(list: List): JsonNode = %(asSeq(list))
|
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var BitList) {.raises: [Defect, ValueError].} =
|
2021-01-31 23:33:40 +00:00
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
result = type(result)(hexToSeqByte(n.getStr()))
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-01-31 23:33:40 +00:00
|
|
|
proc `%`*(bitlist: BitList): JsonNode =
|
|
|
|
newJString(toJsonHex(seq[byte](BitSeq(bitlist))))
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var ValidatorSig) {.raises: [Defect, ValueError].} =
|
2020-06-29 17:30:19 +00:00
|
|
|
n.kind.expect(JString, argName)
|
2020-05-22 17:04:52 +00:00
|
|
|
result = ValidatorSig.fromHex(n.getStr()).tryGet()
|
|
|
|
|
|
|
|
proc `%`*(value: ValidatorSig): JsonNode =
|
2020-10-28 18:51:38 +00:00
|
|
|
newJString(toJsonHex(toRaw(value)))
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var TrustedSig) {.raises: [Defect, ValueError].} =
|
2021-01-31 23:33:40 +00:00
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
hexToByteArray(n.getStr(), result.data)
|
|
|
|
|
|
|
|
proc `%`*(value: TrustedSig): JsonNode =
|
|
|
|
newJString(toJsonHex(toRaw(value)))
|
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var Version) {.raises: [Defect, ValueError].} =
|
2020-06-29 17:30:19 +00:00
|
|
|
n.kind.expect(JString, argName)
|
2020-05-27 17:06:28 +00:00
|
|
|
hexToByteArray(n.getStr(), array[4, byte](result))
|
|
|
|
|
2022-01-06 07:38:40 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var JustificationBits) {.raises: [Defect, ValueError].} =
|
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
result = JustificationBits(hexToByteArray(n.getStr(), 1)[0])
|
|
|
|
|
2020-05-27 17:06:28 +00:00
|
|
|
proc `%`*(value: Version): JsonNode =
|
2020-10-28 18:51:38 +00:00
|
|
|
newJString(toJsonHex(distinctBase(value)))
|
2020-05-27 17:06:28 +00:00
|
|
|
|
2020-10-07 13:02:54 +00:00
|
|
|
template genFromJsonForIntType(T: untyped) =
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var T) {.raises: [Defect, ValueError].} =
|
2020-05-22 17:04:52 +00:00
|
|
|
n.kind.expect(JInt, argName)
|
2020-10-28 18:51:38 +00:00
|
|
|
let asInt = n.getBiggestInt()
|
2020-11-27 19:48:33 +00:00
|
|
|
when T is Epoch:
|
|
|
|
if asInt == -1:
|
|
|
|
# TODO: This is a major hack here. Since the json library
|
|
|
|
# cannot handle properly 0xffffffff when serializing and
|
|
|
|
# deserializing uint64 values, we detect one known wrong
|
|
|
|
# result, appering in most `Validator` records. To fix
|
|
|
|
# this issue, we'll have to switch to nim-json-serialization
|
|
|
|
# in nim-json-rpc or work towards implementing a fix upstream.
|
|
|
|
result = FAR_FUTURE_EPOCH
|
|
|
|
return
|
2020-10-07 13:02:54 +00:00
|
|
|
if asInt < 0:
|
2020-11-27 19:48:33 +00:00
|
|
|
# signed -> unsigned conversions are unchecked
|
|
|
|
# https://github.com/nim-lang/RFCs/issues/175
|
2020-10-07 13:02:54 +00:00
|
|
|
raise newException(
|
|
|
|
ValueError, "JSON-RPC input is an unexpected negative value")
|
|
|
|
result = T(asInt)
|
2020-05-22 17:04:52 +00:00
|
|
|
|
|
|
|
genFromJsonForIntType(Epoch)
|
|
|
|
genFromJsonForIntType(Slot)
|
|
|
|
genFromJsonForIntType(CommitteeIndex)
|
2020-09-14 11:13:30 +00:00
|
|
|
genFromJsonForIntType(ValidatorIndex)
|
2020-05-22 17:04:52 +00:00
|
|
|
|
2021-03-26 14:11:06 +00:00
|
|
|
proc `%`*(value: Epoch): JsonNode =
|
|
|
|
# In nim <= 1.2.6, `uint64` was silently cast to int64 resulting in
|
|
|
|
# FAR_FUTURE_EPOCH showing as -1 - this is a hack to maintain that behaviour
|
|
|
|
# in a world where a Defect or an actual correct value is used - the eth2
|
|
|
|
# REST api instead prints all epochs and similar large numbers as strings!
|
|
|
|
# See also https://github.com/status-im/nimbus-eth2/issues/2430
|
|
|
|
newJInt(cast[int64](value))
|
|
|
|
|
|
|
|
proc `%`*(value: Slot): JsonNode =
|
|
|
|
newJInt(cast[int64](value))
|
|
|
|
|
2020-10-28 18:51:38 +00:00
|
|
|
proc `%`*(value: GraffitiBytes): JsonNode =
|
|
|
|
newJString(toJsonHex(distinctBase(value)))
|
2020-06-29 17:30:19 +00:00
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, value: var GraffitiBytes) {.raises: [Defect, ValueError].} =
|
2020-06-29 17:30:19 +00:00
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
value = GraffitiBytes.init n.getStr()
|
|
|
|
|
2020-05-22 17:04:52 +00:00
|
|
|
proc `%`*(value: CommitteeIndex): JsonNode =
|
2020-10-28 18:51:38 +00:00
|
|
|
newJInt(value.BiggestInt)
|
2020-09-14 11:13:30 +00:00
|
|
|
|
|
|
|
proc `%`*(value: ValidatorIndex): JsonNode =
|
2020-10-28 18:51:38 +00:00
|
|
|
newJInt(value.BiggestInt)
|
|
|
|
|
|
|
|
proc `%`*(value: Eth2Digest): JsonNode =
|
|
|
|
newJString(toJsonHex(value.data))
|
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var Eth2Digest) {.raises: [Defect, ValueError].} =
|
2020-10-28 18:51:38 +00:00
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
hexToByteArray(n.getStr(), result.data)
|
2021-01-31 23:33:40 +00:00
|
|
|
|
|
|
|
proc `%`*(value: BitSeq): JsonNode =
|
|
|
|
newJString(toJsonHex(value.bytes))
|
|
|
|
|
2021-03-26 06:52:01 +00:00
|
|
|
proc fromJson*(n: JsonNode, argName: string, result: var BitSeq) {.raises: [Defect, ValueError].} =
|
2021-01-31 23:33:40 +00:00
|
|
|
n.kind.expect(JString, argName)
|
|
|
|
result = BitSeq(hexToSeqByte(n.getStr()))
|
2022-01-06 07:38:40 +00:00
|
|
|
|
|
|
|
proc `%`*(value: JustificationBits): JsonNode =
|
|
|
|
newJString(toJsonHex([distinctBase(value)]))
|