1pub mod balances;
17pub mod eth1_data_votes;
18pub mod fifo_queue;
19pub mod inactivity_scores;
20pub mod participation;
21pub mod randao_mixes;
22pub mod recent_roots;
23pub mod slashings;
24pub mod types;
25pub mod validators;
26
27use rkyv::{Archive, Deserialize, Serialize};
28
29use crate::types::{
30 BalancesDiff, Eth1DataVotesDiff, FifoQueueDiff, InactivityDiff, ParticipationDiff, RandaoDiff,
31 RootsDiff, SlashingsDiff, ValidatorsDiff,
32};
33
34#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
39pub enum ForkName {
40 Phase0,
41 Altair,
42 Bellatrix,
43 Capella,
44 Deneb,
45 Electra,
46 Fulu,
47}
48
49#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
57pub struct BeaconStateDelta {
58 pub fork: ForkName,
59 pub base_slot: u64,
60 pub scalar_header: Vec<u8>,
61
62 pub balances: BalancesDiff,
63 pub previous_participation: ParticipationDiff,
64 pub validators: ValidatorsDiff,
65 pub block_roots: RootsDiff,
66 pub state_roots: RootsDiff,
67 pub randao_mixes: RandaoDiff,
68 pub slashings: SlashingsDiff,
69 pub inactivity_scores: InactivityDiff,
70
71 pub eth1_data_votes: Eth1DataVotesDiff,
72
73 pub pending_deposits: FifoQueueDiff,
74 pub pending_partial_withdrawals: FifoQueueDiff,
75 pub pending_consolidations: FifoQueueDiff,
76}
77
78pub trait DiffTarget {
86 fn get_fork(&self) -> ForkName;
87 fn scalar_header_mut(&mut self) -> &mut Vec<u8>;
88
89 fn balances_mut(&mut self) -> &mut Vec<u64>;
90 fn previous_participation_mut(&mut self) -> &mut Vec<u8>;
91 fn validators_mut(&mut self) -> &mut Vec<u8>;
92 fn block_roots_mut(&mut self) -> &mut [[u8; 32]];
93 fn state_roots_mut(&mut self) -> &mut [[u8; 32]];
94 fn randao_mixes_mut(&mut self) -> &mut [[u8; 32]];
95 fn slashings_mut(&mut self) -> &mut [u64];
96 fn inactivity_scores_mut(&mut self) -> &mut Vec<u64>;
97
98 fn eth1_data_votes_mut(&mut self) -> &mut Vec<u8>;
99
100 fn pending_deposits_mut(&mut self) -> &mut Vec<u8>;
101 fn pending_partial_withdrawals_mut(&mut self) -> &mut Vec<u8>;
102 fn pending_consolidations_mut(&mut self) -> &mut Vec<u8>;
103}
104
105pub fn apply<M: DiffTarget>(mut state: M, delta: &ArchivedBeaconStateDelta) -> M {
120 use rkyv::deserialize;
121
122 let delta_fork: ForkName = deserialize::<ForkName, rkyv::rancor::Error>(&delta.fork)
123 .expect("failed to deserialize fork");
124
125 let state_fork = state.get_fork();
126 assert_eq!(
127 state_fork, delta_fork,
128 "Fork mismatch: cannot apply {delta_fork:?} delta to {state_fork:?} state",
129 );
130
131 let base_slot = delta.base_slot.to_native();
132 let slots_per_epoch: u64 = 32;
133
134 *state.scalar_header_mut() = delta.scalar_header.as_slice().to_vec();
135
136 balances::apply_balances(state.balances_mut(), &delta.balances);
137 participation::apply_participation(
138 state.previous_participation_mut(),
139 &delta.previous_participation,
140 );
141 validators::apply_validators(state.validators_mut(), &delta.validators);
142
143 recent_roots::apply_roots(base_slot, state.block_roots_mut(), &delta.block_roots);
144 recent_roots::apply_roots(base_slot, state.state_roots_mut(), &delta.state_roots);
145 randao_mixes::apply_randao(
146 base_slot,
147 state.randao_mixes_mut(),
148 &delta.randao_mixes,
149 slots_per_epoch,
150 );
151 slashings::apply_slashings(state.slashings_mut(), &delta.slashings);
152 inactivity_scores::apply_inactivity(state.inactivity_scores_mut(), &delta.inactivity_scores);
153
154 eth1_data_votes::apply_eth1_votes(state.eth1_data_votes_mut(), &delta.eth1_data_votes);
155
156 fifo_queue::apply_fifo_queue(state.pending_deposits_mut(), &delta.pending_deposits, 88);
157 fifo_queue::apply_fifo_queue(
158 state.pending_partial_withdrawals_mut(),
159 &delta.pending_partial_withdrawals,
160 121,
161 );
162 fifo_queue::apply_fifo_queue(
163 state.pending_consolidations_mut(),
164 &delta.pending_consolidations,
165 169,
166 );
167
168 state
169}
170
171pub trait DiffSource {
179 fn fork(&self) -> ForkName;
180 fn slot(&self) -> (u64, u64);
181 fn scalar_header(&self) -> Vec<u8>;
182
183 fn balances(&self) -> (&[u64], &[u64]);
184 fn previous_participation(&self) -> (&[u8], &[u8]);
185 fn validators(&self) -> (&[u8], &[u8]);
186
187 fn block_roots(&self) -> &[[u8; 32]];
188 fn state_roots(&self) -> &[[u8; 32]];
189 fn randao_mixes(&self) -> &[[u8; 32]];
190 fn slashings(&self) -> (&[u64], &[u64]);
191 fn inactivity_scores(&self) -> (&[u64], &[u64]);
192
193 fn eth1_data_votes(&self) -> (&[u8], &[u8]);
194
195 fn pending_deposits(&self) -> FifoQueueDiff;
196 fn pending_partial_withdrawals(&self) -> FifoQueueDiff;
197 fn pending_consolidations(&self) -> FifoQueueDiff;
198}
199
200pub fn create<R: DiffSource>(state: &R) -> BeaconStateDelta {
212 let (base_balances, target_balances) = state.balances();
213 let (base_prev_participation, target_prev_participation) = state.previous_participation();
214 let (base_validators, target_validators) = state.validators();
215 let (base_inactivity, target_inactivity) = state.inactivity_scores();
216 let (base_slashings, target_slashings) = state.slashings();
217 let (base_eth1_data_votes, target_eth1_data_votes) = state.eth1_data_votes();
218
219 let (base_slot, target_slot) = state.slot();
220 let slots_per_epoch: u64 = 32;
221
222 BeaconStateDelta {
223 fork: state.fork(),
224 base_slot,
225 scalar_header: state.scalar_header(),
226
227 balances: balances::diff_balances(base_balances, target_balances),
228 previous_participation: participation::diff_participation(
229 base_prev_participation,
230 target_prev_participation,
231 ),
232 validators: validators::diff_validators(base_validators, target_validators),
233
234 block_roots: recent_roots::diff_roots(base_slot, target_slot, state.block_roots()),
235 state_roots: recent_roots::diff_roots(
236 base_slot,
237 base_slot + slots_per_epoch,
238 state.state_roots(),
239 ),
240 randao_mixes: randao_mixes::diff_randao(
241 base_slot,
242 base_slot + slots_per_epoch,
243 state.randao_mixes(),
244 slots_per_epoch,
245 ),
246 slashings: slashings::diff_slashings(
247 base_slot,
248 base_slot + slots_per_epoch,
249 base_slashings,
250 target_slashings,
251 slots_per_epoch,
252 ),
253 inactivity_scores: inactivity_scores::diff_inactivity(base_inactivity, target_inactivity),
254
255 eth1_data_votes: eth1_data_votes::diff_eth1_votes(
256 base_eth1_data_votes,
257 target_eth1_data_votes,
258 ),
259
260 pending_deposits: state.pending_deposits(),
261 pending_partial_withdrawals: state.pending_partial_withdrawals(),
262 pending_consolidations: state.pending_consolidations(),
263 }
264}