ethexe_common/
consensus.rs1use crate::{
5 Address, Digest, ProtocolTimelines, ToDigest,
6 ecdsa::{ContractSignature, VerifiedData},
7 gear::BatchCommitment,
8 validators::ValidatorsVec,
9};
10use alloc::vec::Vec;
11use core::num::NonZeroUsize;
12use gprimitives::{CodeId, H256};
13use k256::sha2::Digest as _;
14use parity_scale_codec::{Decode, Encode};
15use sha3::Keccak256;
16
17pub const MAX_BATCH_SIZE_LIMIT: u64 = 120 * 1024;
19
20pub const DEFAULT_BATCH_SIZE_LIMIT: u64 = 100 * 1024;
22
23pub type VerifiedValidationRequest = VerifiedData<BatchCommitmentValidationRequest>;
24pub type VerifiedValidationReply = VerifiedData<BatchCommitmentValidationReply>;
25
26pub const fn block_coordinator_index_for_slot(validators_amount: NonZeroUsize, slot: u64) -> usize {
29 (slot % validators_amount.get() as u64) as usize
30}
31
32impl ProtocolTimelines {
33 pub fn block_coordinator_at(
46 &self,
47 validators: &ValidatorsVec,
48 timestamp: u64,
49 ) -> Option<Address> {
50 let idx = self.block_coordinator_index_at(validators.len_nonzero(), timestamp)?;
51 validators.get(idx).cloned()
52 }
53
54 pub fn block_coordinator_index_at(
62 &self,
63 validators_amount: NonZeroUsize,
64 timestamp: u64,
65 ) -> Option<usize> {
66 let slot = self.slot_from_ts(timestamp)?;
67 Some(block_coordinator_index_for_slot(validators_amount, slot))
68 }
69}
70
71#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
73pub struct BatchCommitmentValidationRequest {
74 pub digest: Digest,
76 pub head: Option<H256>,
79 pub codes: Vec<CodeId>,
81 pub rewards: bool,
83 pub validators: bool,
85}
86
87impl BatchCommitmentValidationRequest {
88 pub fn new(batch: &BatchCommitment) -> Self {
89 let codes = batch
90 .code_commitments
91 .iter()
92 .map(|commitment| commitment.id)
93 .collect();
94
95 BatchCommitmentValidationRequest {
96 digest: batch.to_digest(),
97 head: batch.chain_commitment.as_ref().map(|cc| cc.head),
98 codes,
99 rewards: batch.rewards_commitment.is_some(),
100 validators: batch.validators_commitment.is_some(),
101 }
102 }
103}
104
105impl ToDigest for BatchCommitmentValidationRequest {
106 fn update_hasher(&self, hasher: &mut sha3::Keccak256) {
107 let Self {
108 digest,
109 head,
110 codes,
111 rewards,
112 validators,
113 } = self;
114
115 hasher.update(digest);
116 head.map(|h| hasher.update(h.0));
117 hasher.update(
118 codes
119 .iter()
120 .flat_map(|h| h.into_bytes())
121 .collect::<Vec<u8>>(),
122 );
123 hasher.update([*rewards as u8]);
124 hasher.update([*validators as u8]);
125 }
126}
127
128#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
131pub struct BatchCommitmentValidationReply {
132 pub digest: Digest,
134 pub signature: ContractSignature,
136}
137
138impl ToDigest for BatchCommitmentValidationReply {
139 fn update_hasher(&self, hasher: &mut Keccak256) {
140 let Self { digest, signature } = self;
141 hasher.update(digest.0);
142 hasher.update(signature.into_pre_eip155_bytes())
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use core::num::NonZeroU64;
150
151 #[test]
152 fn block_coordinator_index_calculates_correct_index() {
153 let validators_amount = NonZeroUsize::new(5).unwrap();
154 let slot = 7;
155
156 let index = block_coordinator_index_for_slot(validators_amount, slot);
157
158 assert_eq!(index, 2);
159 }
160
161 #[test]
162 fn block_coordinator_for_calculates_correct_coordinator() {
163 let validators: ValidatorsVec = vec![
164 Address::from([1; 20]),
165 Address::from([2; 20]),
166 Address::from([3; 20]),
167 ]
168 .try_into()
169 .unwrap();
170
171 let coordinator = ProtocolTimelines {
172 slot: NonZeroU64::new(1).unwrap(),
173 genesis_ts: 0,
174 era: NonZeroU64::new(1).unwrap(),
175 election: 0,
176 }
177 .block_coordinator_at(&validators, 10);
178
179 assert_eq!(coordinator, Some(Address::from([2; 20])));
180 }
181
182 #[test]
183 fn block_coordinator_for_calculates_correct_coordinator_with_genesis_timestamp() {
184 let validators: ValidatorsVec = vec![
185 Address::from([1; 20]),
186 Address::from([2; 20]),
187 Address::from([3; 20]),
188 ]
189 .try_into()
190 .unwrap();
191
192 let coordinator = ProtocolTimelines {
193 slot: NonZeroU64::new(2).unwrap(),
194 genesis_ts: 6,
195 era: NonZeroU64::new(1).unwrap(),
196 election: 0,
197 }
198 .block_coordinator_at(&validators, 16);
199
200 assert_eq!(coordinator, Some(Address::from([3; 20])));
201 }
202
203 #[test]
204 fn block_coordinator_at_returns_none_before_genesis() {
205 let validators: ValidatorsVec = vec![Address::from([1; 20])].try_into().unwrap();
206
207 let coordinator = ProtocolTimelines {
208 slot: NonZeroU64::new(1).unwrap(),
209 genesis_ts: 100,
210 era: NonZeroU64::new(1).unwrap(),
211 election: 0,
212 }
213 .block_coordinator_at(&validators, 50);
214
215 assert_eq!(coordinator, None);
216 }
217}