Skip to content

Commit

Permalink
Use the new strict Json flavors mechanism for RestJson (#5674)
Browse files Browse the repository at this point in the history
This requires all object types to be explicitly white-listed for
default serialization. The PR makes the minimal changes, although
a number of similar mechanisms in eth2_rest_serialization can now
be removed.
  • Loading branch information
zah authored Dec 19, 2023
1 parent f125a5c commit 29b29e1
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 34 deletions.
4 changes: 3 additions & 1 deletion beacon_chain/el/el_manager.nim
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ type
Eth1BlockNumber* = uint64
Eth1BlockTimestamp* = uint64

Eth1Block* = ref object
Eth1BlockObj* = object
hash*: Eth2Digest
number*: Eth1BlockNumber
timestamp*: Eth1BlockTimestamp
Expand All @@ -111,6 +111,8 @@ type
## Global deposits count and hash tree root of the entire sequence
## These are computed when the block is added to the chain (see `addBlock`)

Eth1Block* = ref Eth1BlockObj

Eth1Chain* = object
db: BeaconChainDB
cfg: RuntimeConfig
Expand Down
14 changes: 14 additions & 0 deletions beacon_chain/rpc/rest_nimbus_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,20 @@ type
peerId*: PeerId
connected*: bool

RestJson.useDefaultSerializationFor(
BlockProposalEth1Data,
Eth1BlockObj,
RestChronosMetricsInfo,
RestConnectionInfo,
RestFutureInfo,
RestPeerInfo,
RestPeerInfoTuple,
RestPeerStats,
RestPeerStatus,
RestPubSubPeer,
RestSimplePeer,
)

proc toInfo(node: BeaconNode, peerId: PeerId): RestPeerInfo =
RestPeerInfo(
peerId: $peerId,
Expand Down
4 changes: 4 additions & 0 deletions beacon_chain/rpc/rest_node_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type
connected*: uint64
disconnecting*: uint64

RestJson.useDefaultSerializationFor(
RestNodePeerCount,
)

proc validateState(states: seq[PeerStateKind]): Result[ConnectionStateSet,
cstring] =
var res: set[ConnectionState]
Expand Down
248 changes: 217 additions & 31 deletions beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import std/[typetraits, strutils]
import stew/[assign2, results, base10, byteutils, endians2], presto/common,
libp2p/peerid, serialization, json_serialization,
json_serialization/std/[net, sets], stint,
chronicles
json_serialization/std/[net, sets],
json_serialization/stew/results as jsonSerializationResults,
stint, chronicles
import ".."/[eth2_ssz_serialization, forks, keystore],
".."/../consensus_object_pools/block_pools_types,
".."/datatypes/[phase0, altair, bellatrix],
Expand All @@ -25,7 +26,8 @@ from ".."/datatypes/deneb import BeaconState

export
eth2_ssz_serialization, results, peerid, common, serialization, chronicles,
json_serialization, net, sets, rest_types, slashing_protection_common
json_serialization, net, sets, rest_types, slashing_protection_common,
jsonSerializationResults

from web3/primitives import BlockHash
export primitives.BlockHash
Expand All @@ -36,7 +38,218 @@ func decodeMediaType*(
return err("Missing or incorrect Content-Type")
ok contentType.get.mediaType

Json.createFlavor RestJson
type
EmptyBody* = object

createJsonFlavor RestJson

RestJson.useDefaultSerializationFor(
AggregateAndProof,
Attestation,
AttestationData,
AttesterSlashing,
BLSToExecutionChange,
BeaconBlockHeader,
BlobSidecar,
BlobsBundle,
Checkpoint,
ContributionAndProof,
DataEnclosedObject,
DataMetaEnclosedObject,
DataOptimisticAndFinalizedObject,
DataOptimisticObject,
DataRootEnclosedObject,
DataVersionEnclosedObject,
DeleteKeystoresBody,
DeleteKeystoresResponse,
DeleteRemoteKeystoresResponse,
DenebSignedBlockContents,
Deposit,
DepositData,
DistributedKeystoreInfo,
EmptyBody,
Eth1Data,
EventBeaconBlockObject,
ExecutionPayloadAndBlobsBundle,
Fork,
GetBlockAttestationsResponse,
GetBlockHeaderResponse,
GetBlockHeadersResponse,
GetDepositContractResponse,
GetDepositSnapshotResponse,
GetDistributedKeystoresResponse,
GetEpochCommitteesResponse,
GetEpochSyncCommitteesResponse,
GetForkChoiceResponse,
GetForkScheduleResponse,
GetGenesisResponse,
GetHeaderResponseCapella,
GetHeaderResponseDeneb,
GetKeystoresResponse,
GetNextWithdrawalsResponse,
GetPoolAttesterSlashingsResponse,
GetPoolProposerSlashingsResponse,
GetPoolVoluntaryExitsResponse,
GetRemoteKeystoresResponse,
GetSpecVCResponse,
GetStateFinalityCheckpointsResponse,
GetStateForkResponse,
GetStateRandaoResponse,
GetStateRootResponse,
GetStateValidatorBalancesResponse,
GetStateValidatorResponse,
GetStateValidatorsResponse,
GetValidatorGasLimitResponse,
HistoricalSummary,
ImportDistributedKeystoresBody,
ImportRemoteKeystoresBody,
IndexedAttestation,
KeymanagerGenericError,
KeystoreInfo,
ListFeeRecipientResponse,
ListGasLimitResponse,
PendingAttestation,
PostKeystoresResponse,
PrepareBeaconProposer,
ProposerSlashing,
RemoteKeystoreInfo,
RemoteSignerInfo,
RequestItemStatus,
RestAttesterDuty,
RestBeaconCommitteeSelection,
RestBeaconStatesCommittees,
RestBeaconStatesFinalityCheckpoints,
RestBlockHeader,
RestBlockHeaderInfo,
RestCommitteeSubscription,
RestContributionAndProof,
RestDepositContract,
RestDepositSnapshot,
RestEpochRandao,
RestEpochSyncCommittee,
RestExecutionPayload,
RestExtraData,
RestGenesis,
RestIndexedErrorMessage,
RestIndexedErrorMessageItem,
RestMetadata,
RestNetworkIdentity,
RestNimbusTimestamp1,
RestNimbusTimestamp2,
RestNode,
RestNodeExtraData,
RestNodePeer,
RestNodeVersion,
RestPeerCount,
RestProposerDuty,
RestRoot,
RestSignedBlockHeader,
RestSignedContributionAndProof,
RestSyncCommitteeContribution,
RestSyncCommitteeDuty,
RestSyncCommitteeMessage,
RestSyncCommitteeSelection,
RestSyncCommitteeSubscription,
RestSyncInfo,
RestValidator,
RestValidatorBalance,
SPDIR,
SPDIR_Meta,
SPDIR_SignedAttestation,
SPDIR_SignedBlock,
SPDIR_Validator,
SetFeeRecipientRequest,
SetGasLimitRequest,
SignedAggregateAndProof,
SignedBLSToExecutionChange,
SignedBeaconBlockHeader,
SignedContributionAndProof,
SignedValidatorRegistrationV1,
SignedVoluntaryExit,
SubmitBlindedBlockResponseCapella,
SubmitBlindedBlockResponseDeneb,
SyncAggregate,
SyncAggregatorSelectionData,
SyncCommittee,
SyncCommitteeContribution,
SyncCommitteeMessage,
TrustedAttestation,
Validator,
ValidatorRegistrationV1,
VoluntaryExit,
Web3SignerAggregationSlotData,
Web3SignerDepositData,
Web3SignerErrorResponse,
Web3SignerForkInfo,
Web3SignerMerkleProof,
Web3SignerRandaoRevealData,
Web3SignerSignatureResponse,
Web3SignerStatusResponse,
Web3SignerSyncCommitteeMessageData,
Web3SignerValidatorRegistration,
Withdrawal,
altair.BeaconBlock,
altair.BeaconBlockBody,
altair.BeaconState,
altair.LightClientBootstrap,
altair.LightClientFinalityUpdate,
altair.LightClientHeader,
altair.LightClientOptimisticUpdate,
altair.LightClientUpdate,
altair.SignedBeaconBlock,
bellatrix.BeaconBlock,
bellatrix.BeaconBlockBody,
bellatrix.BeaconState,
bellatrix.ExecutionPayload,
bellatrix.ExecutionPayloadHeader,
bellatrix.SignedBeaconBlock,
bellatrix_mev.BlindedBeaconBlock,
bellatrix_mev.SignedBlindedBeaconBlock,
capella.BeaconBlock,
capella.BeaconBlockBody,
capella.BeaconState,
capella.ExecutionPayload,
capella.ExecutionPayloadHeader,
capella.LightClientBootstrap,
capella.LightClientFinalityUpdate,
capella.LightClientHeader,
capella.LightClientOptimisticUpdate,
capella.LightClientUpdate,
capella.SignedBeaconBlock,
capella_mev.BlindedBeaconBlock,
capella_mev.BlindedBeaconBlockBody,
capella_mev.BuilderBid,
capella_mev.SignedBlindedBeaconBlock,
capella_mev.SignedBuilderBid,
deneb.BeaconBlock,
deneb.BeaconBlockBody,
deneb.BeaconState,
deneb.BlockContents,
deneb.ExecutionPayload,
deneb.ExecutionPayloadHeader,
deneb.LightClientBootstrap,
deneb.LightClientFinalityUpdate,
deneb.LightClientHeader,
deneb.LightClientOptimisticUpdate,
deneb.LightClientUpdate,
deneb.SignedBeaconBlock,
deneb_mev.BlindedBeaconBlock,
deneb_mev.BlindedBeaconBlockBody,
deneb_mev.BuilderBid,
deneb_mev.SignedBlindedBeaconBlock,
deneb_mev.SignedBuilderBid,
phase0.BeaconBlock,
phase0.BeaconBlockBody,
phase0.BeaconState,
phase0.SignedBeaconBlock,
)

# TODO
# Tuples are widely used in the responses of the REST server
# If we switch to concrete types there, it would be possible
# to remove this overly generic definition.
template writeValue*(w: JsonWriter[RestJson], value: tuple) =
writeRecordValue(w, value)

## The RestJson format implements JSON serialization in the way specified
## by the Beacon API:
Expand Down Expand Up @@ -84,8 +297,6 @@ const
UnexpectedDecodeError = "Unexpected decoding error"

type
EmptyBody* = object

EncodeTypes* =
AttesterSlashing |
DeleteKeystoresBody |
Expand Down Expand Up @@ -3087,37 +3298,12 @@ proc writeValue*(
writer.writeField("execution_optimistic", value.optimistic.get())
writer.endRecord()

## EventBeaconBlockObject
proc writeValue*(
writer: var JsonWriter[RestJson], value: EventBeaconBlockObject
) {.raises: [IOError].} =
writer.beginRecord()
writer.writeField("slot", value.slot)
writer.writeField("block", value.block_root)
if value.optimistic.isSome():
writer.writeField("execution_optimistic", value.optimistic.get())
writer.endRecord()

## RestNodeValidity
proc writeValue*(
writer: var JsonWriter[RestJson], value: RestNodeValidity
) {.raises: [IOError].} =
writer.writeValue($value)

## RestSyncInfo
proc writeValue*(
writer: var JsonWriter[RestJson], value: RestSyncInfo
) {.raises: [IOError].} =
writer.beginRecord()
writer.writeField("head_slot", value.head_slot)
writer.writeField("sync_distance", value.sync_distance)
writer.writeField("is_syncing", value.is_syncing)
if value.is_optimistic.isSome():
writer.writeField("is_optimistic", value.is_optimistic.get())
if value.el_offline.isSome():
writer.writeField("el_offline", value.el_offline.get())
writer.endRecord()

## RestErrorMessage
proc readValue*(reader: var JsonReader[RestJson],
value: var RestErrorMessage) {.
Expand Down
5 changes: 5 additions & 0 deletions tests/test_validator_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ type
SyncCommitteeBitsObject = object
data: SyncCommitteeAggregationBits

RestJson.useDefaultSerializationFor(
AttestationBitsObject,
SyncCommitteeBitsObject
)

const
AttestationDataVectors = [
# Attestation score with block monitoring enabled (perfect).
Expand Down

0 comments on commit 29b29e1

Please sign in to comment.