77import std/ typetraits
88import stew/ [assign2, results, base10, byteutils], presto/ common,
99 libp2p/ peerid, serialization, json_serialization,
10- json_serialization/ std/ [options, net, sets]
10+ json_serialization/ std/ [options, net, sets],
11+ chronicles
1112import " .." / [eth2_ssz_serialization, forks, keystore],
1213 " .." / datatypes/ [phase0, altair, bellatrix],
1314 " .." / mev/ bellatrix_mev,
@@ -16,14 +17,41 @@ import ".."/[eth2_ssz_serialization, forks, keystore],
1617import nimcrypto/ utils as ncrutils
1718
1819export
19- eth2_ssz_serialization, results, peerid, common, serialization,
20+ eth2_ssz_serialization, results, peerid, common, serialization, chronicles,
2021 json_serialization, options, net, sets, rest_types, slashing_protection_common
2122
2223from web3/ ethtypes import BlockHash
2324export ethtypes.BlockHash
2425
2526Json .createFlavor RestJson
2627
28+ # # The RestJson format implements JSON serialization in the way specified
29+ # # by the Beacon API:
30+ # #
31+ # # https://ethereum.github.io/beacon-APIs/
32+ # #
33+ # # In this format, we must always set `allowUnknownFields = true` in the
34+ # # decode calls in order to conform the following spec:
35+ # #
36+ # # All JSON responses return the requested data under a data key in the top
37+ # # level of their response. Additional metadata may or may not be present
38+ # # in other keys at the top level of the response, dependent on the endpoint.
39+ # # The rules that require an increase in version number are as follows:
40+ # #
41+ # # - no field that is listed in an endpoint shall be removed without an increase
42+ # # in the version number
43+ # #
44+ # # - no field that is listed in an endpoint shall be altered in terms of format
45+ # # (e.g. from a string to an array) without an increase in the version number
46+ # #
47+ # # Note that it is possible for a field to be added to an endpoint's data or
48+ # # metadata without an increase in the version number.
49+ # #
50+ # # TODO nim-json-serializations should allow setting up this policy per format
51+ # #
52+ # # This also means that when new fields are introduced to the object definitions
53+ # # below, one must use the `Option[T]` type.
54+
2755const
2856 DecimalSet = {'0' .. '9' }
2957 # Base10 (decimal) set of chars
93121 Web3SignerSignatureResponse |
94122 Web3SignerStatusResponse
95123
96- # These types may be extended with additional fields in the future.
97- # Locally unknown fields are silently ignored when decoding them.
98- ExtensibleDecodeTypes * =
99- GetSpecResponse |
100- GetSpecVCResponse
101-
102124 SszDecodeTypes * =
103125 GetPhase0StateSszResponse |
104126 GetPhase0BlockSszResponse
@@ -338,7 +360,9 @@ proc decodeJsonString*[T](t: typedesc[T],
338360 data: JsonString ,
339361 requireAllFields = true ): Result [T, cstring ] =
340362 try :
341- ok (RestJson .decode (string (data), T, requireAllFields = requireAllFields))
363+ ok (RestJson .decode (string (data), T,
364+ requireAllFields = requireAllFields,
365+ allowUnknownFields = true ))
342366 except SerializationError :
343367 err (" Unable to deserialize data" )
344368
@@ -664,6 +688,13 @@ proc readValue*(
664688 raiseUnexpectedValue (
665689 reader, " Expected a valid hex string with " & $ value.len () & " bytes" )
666690
691+ template unrecognizedFieldWarning =
692+ # TODO : There should be a different notification mechanism for informing the
693+ # caller of a deserialization routine for unexpected fields.
694+ # The chonicles import in this module should be removed.
695+ debug " JSON field not recognized by the current version of Nimbus. Consider upgrading" ,
696+ fieldName, typeName = typetraits.name (typeof value)
697+
667698# # ForkedBeaconBlock
668699proc readValue * [BlockType: Web3SignerForkedBeaconBlock | ForkedBeaconBlock ](
669700 reader: var JsonReader [RestJson ],
@@ -694,7 +725,7 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
694725 " ForkedBeaconBlock" )
695726 data = some (reader.readValue (JsonString ))
696727 else :
697- reader. raiseUnexpectedField (fieldName, " ForkedBeaconBlock " )
728+ unrecognizedFieldWarning ( )
698729
699730 if version.isNone ():
700731 reader.raiseUnexpectedValue (" Field version is missing" )
@@ -705,8 +736,10 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
705736 of BeaconBlockFork .Phase0 :
706737 let res =
707738 try :
708- some (RestJson .decode (string (data.get ()), phase0.BeaconBlock ,
709- requireAllFields = true ))
739+ some (RestJson .decode (string (data.get ()),
740+ phase0.BeaconBlock ,
741+ requireAllFields = true ,
742+ allowUnknownFields = true ))
710743 except SerializationError :
711744 none [phase0.BeaconBlock ]()
712745 if res.isNone ():
@@ -715,8 +748,10 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
715748 of BeaconBlockFork .Altair :
716749 let res =
717750 try :
718- some (RestJson .decode (string (data.get ()), altair.BeaconBlock ,
719- requireAllFields = true ))
751+ some (RestJson .decode (string (data.get ()),
752+ altair.BeaconBlock ,
753+ requireAllFields = true ,
754+ allowUnknownFields = true ))
720755 except SerializationError :
721756 none [altair.BeaconBlock ]()
722757 if res.isNone ():
@@ -725,8 +760,10 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock|ForkedBeaconBlock](
725760 of BeaconBlockFork .Bellatrix :
726761 let res =
727762 try :
728- some (RestJson .decode (string (data.get ()), bellatrix.BeaconBlock ,
729- requireAllFields = true ))
763+ some (RestJson .decode (string (data.get ()),
764+ bellatrix.BeaconBlock ,
765+ requireAllFields = true ,
766+ allowUnknownFields = true ))
730767 except SerializationError :
731768 none [bellatrix.BeaconBlock ]()
732769 if res.isNone ():
@@ -835,8 +872,7 @@ proc readValue*(reader: var JsonReader[RestJson],
835872 " RestPublishedBeaconBlockBody" )
836873 execution_payload = some (reader.readValue (ExecutionPayload ))
837874 else :
838- # Ignore unknown fields
839- discard
875+ unrecognizedFieldWarning ()
840876
841877 if randao_reveal.isNone ():
842878 reader.raiseUnexpectedValue (" Field `randao_reveal` is missing" )
@@ -949,8 +985,7 @@ proc readValue*(reader: var JsonReader[RestJson],
949985 " RestPublishedBeaconBlock" )
950986 blockBody = some (reader.readValue (RestPublishedBeaconBlockBody ))
951987 else :
952- # Ignore unknown fields
953- discard
988+ unrecognizedFieldWarning ()
954989
955990 if slot.isNone ():
956991 reader.raiseUnexpectedValue (" Field `slot` is missing" )
@@ -1017,8 +1052,7 @@ proc readValue*(reader: var JsonReader[RestJson],
10171052 " RestPublishedSignedBeaconBlock" )
10181053 signature = some (reader.readValue (ValidatorSig ))
10191054 else :
1020- # Ignore unknown fields
1021- discard
1055+ unrecognizedFieldWarning ()
10221056
10231057 if signature.isNone ():
10241058 reader.raiseUnexpectedValue (" Field `signature` is missing" )
@@ -1081,7 +1115,7 @@ proc readValue*(reader: var JsonReader[RestJson],
10811115 " ForkedSignedBeaconBlock" )
10821116 data = some (reader.readValue (JsonString ))
10831117 else :
1084- reader. raiseUnexpectedField (fieldName, " ForkedSignedBeaconBlock " )
1118+ unrecognizedFieldWarning ( )
10851119
10861120 if version.isNone ():
10871121 reader.raiseUnexpectedValue (" Field version is missing" )
@@ -1092,8 +1126,10 @@ proc readValue*(reader: var JsonReader[RestJson],
10921126 of BeaconBlockFork .Phase0 :
10931127 let res =
10941128 try :
1095- some (RestJson .decode (string (data.get ()), phase0.SignedBeaconBlock ,
1096- requireAllFields = true ))
1129+ some (RestJson .decode (string (data.get ()),
1130+ phase0.SignedBeaconBlock ,
1131+ requireAllFields = true ,
1132+ allowUnknownFields = true ))
10971133 except SerializationError :
10981134 none [phase0.SignedBeaconBlock ]()
10991135 if res.isNone ():
@@ -1102,8 +1138,10 @@ proc readValue*(reader: var JsonReader[RestJson],
11021138 of BeaconBlockFork .Altair :
11031139 let res =
11041140 try :
1105- some (RestJson .decode (string (data.get ()), altair.SignedBeaconBlock ,
1106- requireAllFields = true ))
1141+ some (RestJson .decode (string (data.get ()),
1142+ altair.SignedBeaconBlock ,
1143+ requireAllFields = true ,
1144+ allowUnknownFields = true ))
11071145 except SerializationError :
11081146 none [altair.SignedBeaconBlock ]()
11091147 if res.isNone ():
@@ -1112,8 +1150,10 @@ proc readValue*(reader: var JsonReader[RestJson],
11121150 of BeaconBlockFork .Bellatrix :
11131151 let res =
11141152 try :
1115- some (RestJson .decode (string (data.get ()), bellatrix.SignedBeaconBlock ,
1116- requireAllFields = true ))
1153+ some (RestJson .decode (string (data.get ()),
1154+ bellatrix.SignedBeaconBlock ,
1155+ requireAllFields = true ,
1156+ allowUnknownFields = true ))
11171157 except SerializationError :
11181158 none [bellatrix.SignedBeaconBlock ]()
11191159 if res.isNone ():
@@ -1165,7 +1205,7 @@ proc readValue*(reader: var JsonReader[RestJson],
11651205 " ForkedBeaconState" )
11661206 data = some (reader.readValue (JsonString ))
11671207 else :
1168- reader. raiseUnexpectedField (fieldName, " ForkedBeaconState " )
1208+ unrecognizedFieldWarning ( )
11691209
11701210 if version.isNone ():
11711211 reader.raiseUnexpectedValue (" Field version is missing" )
@@ -1188,23 +1228,32 @@ proc readValue*(reader: var JsonReader[RestJson],
11881228 of BeaconStateFork .Phase0 :
11891229 try :
11901230 tmp[].phase0Data.data = RestJson .decode (
1191- string (data.get ()), phase0.BeaconState , requireAllFields = true )
1231+ string (data.get ()),
1232+ phase0.BeaconState ,
1233+ requireAllFields = true ,
1234+ allowUnknownFields = true )
11921235 except SerializationError :
11931236 reader.raiseUnexpectedValue (" Incorrect phase0 beacon state format" )
11941237
11951238 toValue (phase0Data)
11961239 of BeaconStateFork .Altair :
11971240 try :
11981241 tmp[].altairData.data = RestJson .decode (
1199- string (data.get ()), altair.BeaconState , requireAllFields = true )
1242+ string (data.get ()),
1243+ altair.BeaconState ,
1244+ requireAllFields = true ,
1245+ allowUnknownFields = true )
12001246 except SerializationError :
12011247 reader.raiseUnexpectedValue (" Incorrect altair beacon state format" )
12021248
12031249 toValue (altairData)
12041250 of BeaconStateFork .Bellatrix :
12051251 try :
12061252 tmp[].bellatrixData.data = RestJson .decode (
1207- string (data.get ()), bellatrix.BeaconState , requireAllFields = true )
1253+ string (data.get ()),
1254+ bellatrix.BeaconState ,
1255+ requireAllFields = true ,
1256+ allowUnknownFields = true )
12081257 except SerializationError :
12091258 reader.raiseUnexpectedValue (" Incorrect altair beacon state format" )
12101259 toValue (bellatrixData)
@@ -1382,8 +1431,7 @@ proc readValue*(reader: var JsonReader[RestJson],
13821431 dataName = fieldName
13831432 data = some (reader.readValue (JsonString ))
13841433 else :
1385- # We ignore all unknown fields.
1386- discard
1434+ unrecognizedFieldWarning ()
13871435
13881436 if requestKind.isNone ():
13891437 reader.raiseUnexpectedValue (" Field `type` is missing" )
@@ -1620,10 +1668,11 @@ proc readValue*(reader: var JsonReader[RestJson],
16201668 reader.raiseUnexpectedValue (" Invalid `status` value" )
16211669 )
16221670 else :
1623- # We ignore all unknown fields.
1624- discard
1671+ unrecognizedFieldWarning ()
1672+
16251673 if status.isNone ():
16261674 reader.raiseUnexpectedValue (" Field `status` is missing" )
1675+
16271676 value = RemoteKeystoreStatus (status: status.get (), message: message)
16281677
16291678# # ScryptSalt
@@ -1675,8 +1724,7 @@ proc readValue*(reader: var JsonReader[RestJson], value: var Pbkdf2Params) {.
16751724 " Pbkdf2Params" )
16761725 salt = some (reader.readValue (Pbkdf2Salt ))
16771726 else :
1678- # Ignore unknown field names.
1679- discard
1727+ unrecognizedFieldWarning ()
16801728
16811729 if dklen.isNone ():
16821730 reader.raiseUnexpectedValue (" Field `dklen` is missing" )
@@ -1749,8 +1797,7 @@ proc readValue*(reader: var JsonReader[RestJson], value: var ScryptParams) {.
17491797 " ScryptParams" )
17501798 salt = some (reader.readValue (ScryptSalt ))
17511799 else :
1752- # Ignore unknown field names.
1753- discard
1800+ unrecognizedFieldWarning ()
17541801
17551802 if dklen.isNone ():
17561803 reader.raiseUnexpectedValue (" Field `dklen` is missing" )
@@ -1833,8 +1880,7 @@ proc readValue*(reader: var JsonReader[RestJson], value: var Keystore) {.
18331880 reader.raiseUnexpectedValue (" Unexpected negative `version` value" )
18341881 version = some (res)
18351882 else :
1836- # Ignore unknown field names.
1837- discard
1883+ unrecognizedFieldWarning ()
18381884
18391885 if crypto.isNone ():
18401886 reader.raiseUnexpectedValue (" Field `crypto` is missing" )
@@ -1888,8 +1934,7 @@ proc readValue*(reader: var JsonReader[RestJson],
18881934 " KeystoresAndSlashingProtection" )
18891935 slashing = some (reader.readValue (SPDIR ))
18901936 else :
1891- # Ignore unknown field names.
1892- discard
1937+ unrecognizedFieldWarning ()
18931938
18941939 if len (keystores) == 0 :
18951940 reader.raiseUnexpectedValue (" Missing `keystores` value" )
@@ -1912,7 +1957,7 @@ proc decodeBody*[T](t: typedesc[T],
19121957 return err (" Unsupported content type" )
19131958 let data =
19141959 try :
1915- RestJson .decode (body.data, T)
1960+ RestJson .decode (body.data, T, allowUnknownFields = true )
19161961 except SerializationError as exc:
19171962 return err (" Unable to deserialize data" )
19181963 except CatchableError :
@@ -1959,11 +2004,10 @@ proc encodeBytes*[T: EncodeArrays](value: T,
19592004
19602005proc decodeBytes * [T: DecodeTypes ](t: typedesc [T], value: openArray [byte ],
19612006 contentType: string ): RestResult [T] =
1962- const isExtensibleType = t is ExtensibleDecodeTypes
19632007 case contentType
19642008 of " application/json" :
19652009 try :
1966- ok RestJson .decode (value, T, allowUnknownFields = isExtensibleType )
2010+ ok RestJson .decode (value, T, allowUnknownFields = true )
19672011 except SerializationError :
19682012 err (" Serialization error" )
19692013 else :
0 commit comments