Skip to main content

alloy_rpc_types_beacon/
duties.rs

1//! Types for the validator duty endpoints.
2//!
3//! See <https://ethereum.github.io/beacon-APIs/#/Validator>
4
5use crate::BlsPublicKey;
6use alloy_primitives::B256;
7use serde::{Deserialize, Serialize};
8use serde_with::{serde_as, DisplayFromStr};
9
10/// Response from the [`/eth/v1/validator/duties/attester/{epoch}`](https://ethereum.github.io/beacon-APIs/#/Validator/getAttesterDuties) endpoint.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct AttesterDutiesResponse {
13    /// Whether the response references an unverified execution payload.
14    #[serde(default)]
15    pub execution_optimistic: bool,
16    /// The dependent root for the response.
17    pub dependent_root: B256,
18    /// The list of attester duties.
19    pub data: Vec<AttesterDuty>,
20}
21
22/// A single attester duty entry.
23#[serde_as]
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct AttesterDuty {
26    /// The BLS public key of the validator assigned to attest.
27    pub pubkey: BlsPublicKey,
28    /// The index of the validator in the validator registry.
29    #[serde_as(as = "DisplayFromStr")]
30    pub validator_index: u64,
31    /// The committee index.
32    #[serde_as(as = "DisplayFromStr")]
33    pub committee_index: u64,
34    /// The total number of validators in the committee.
35    #[serde_as(as = "DisplayFromStr")]
36    pub committee_length: u64,
37    /// The number of committees at the slot.
38    #[serde_as(as = "DisplayFromStr")]
39    pub committees_at_slot: u64,
40    /// The index of the validator within the committee.
41    #[serde_as(as = "DisplayFromStr")]
42    pub validator_committee_index: u64,
43    /// The slot at which the validator must attest.
44    #[serde_as(as = "DisplayFromStr")]
45    pub slot: u64,
46}
47
48/// Response from the [`/eth/v1/validator/duties/sync/{epoch}`](https://ethereum.github.io/beacon-APIs/#/Validator/getSyncCommitteeDuties) endpoint.
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct SyncCommitteeDutiesResponse {
51    /// Whether the response references an unverified execution payload.
52    #[serde(default)]
53    pub execution_optimistic: bool,
54    /// The list of sync committee duties.
55    pub data: Vec<SyncCommitteeDuty>,
56}
57
58/// A single sync committee duty entry.
59#[serde_as]
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub struct SyncCommitteeDuty {
62    /// The BLS public key of the validator.
63    pub pubkey: BlsPublicKey,
64    /// The index of the validator in the validator registry.
65    #[serde_as(as = "DisplayFromStr")]
66    pub validator_index: u64,
67    /// The indices of the validator in the sync committee.
68    #[serde_as(as = "Vec<DisplayFromStr>")]
69    pub validator_sync_committee_indices: Vec<u64>,
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn serde_attester_duties_response() {
78        let s = r#"{
79            "execution_optimistic": false,
80            "dependent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
81            "data": [
82                {
83                    "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a",
84                    "validator_index": "1",
85                    "committee_index": "1",
86                    "committee_length": "128",
87                    "committees_at_slot": "2",
88                    "validator_committee_index": "25",
89                    "slot": "1"
90                }
91            ]
92        }"#;
93        let resp: AttesterDutiesResponse = serde_json::from_str(s).unwrap();
94        assert_eq!(resp.data.len(), 1);
95        assert_eq!(resp.data[0].validator_index, 1);
96        assert_eq!(resp.data[0].committee_index, 1);
97        assert_eq!(resp.data[0].committee_length, 128);
98        assert_eq!(resp.data[0].committees_at_slot, 2);
99        assert_eq!(resp.data[0].validator_committee_index, 25);
100        assert_eq!(resp.data[0].slot, 1);
101
102        let serialized = serde_json::to_string(&resp).unwrap();
103        let deserialized: AttesterDutiesResponse = serde_json::from_str(&serialized).unwrap();
104        assert_eq!(resp, deserialized);
105    }
106
107    #[test]
108    fn serde_sync_committee_duties_response() {
109        let s = r#"{
110            "execution_optimistic": false,
111            "data": [
112                {
113                    "pubkey": "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a",
114                    "validator_index": "1",
115                    "validator_sync_committee_indices": ["0", "5", "10"]
116                }
117            ]
118        }"#;
119        let resp: SyncCommitteeDutiesResponse = serde_json::from_str(s).unwrap();
120        assert_eq!(resp.data.len(), 1);
121        assert_eq!(resp.data[0].validator_index, 1);
122        assert_eq!(resp.data[0].validator_sync_committee_indices, vec![0, 5, 10]);
123
124        let serialized = serde_json::to_string(&resp).unwrap();
125        let deserialized: SyncCommitteeDutiesResponse = serde_json::from_str(&serialized).unwrap();
126        assert_eq!(resp, deserialized);
127    }
128}