1use crate::{
9 account_address::AccountAddress,
10 block_info::{BlockInfo, Round},
11 epoch_state::EpochState,
12 on_chain_config::ValidatorSet,
13 transaction::Version,
14 validator_verifier::{ValidatorVerifier, VerifyError},
15};
16use diem_crypto::hash::HashValue;
17use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
18#[cfg(any(test, feature = "fuzzing"))]
19use proptest_derive::Arbitrary;
20use serde::{Deserialize, Deserializer, Serialize};
21use std::{
22 collections::BTreeMap,
23 fmt::{Display, Formatter},
24 ops::{Deref, DerefMut},
25};
26
27#[derive(
46 Clone,
47 Debug,
48 Eq,
49 PartialEq,
50 Serialize,
51 Deserialize,
52 CryptoHasher,
53 BCSCryptoHash,
54)]
55#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
56pub struct LedgerInfo {
57 commit_info: BlockInfo,
58
59 consensus_data_hash: HashValue,
62}
63
64impl Display for LedgerInfo {
65 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
66 write!(f, "LedgerInfo: [commit_info: {}]", self.commit_info())
67 }
68}
69
70impl LedgerInfo {
71 pub fn new(commit_info: BlockInfo, consensus_data_hash: HashValue) -> Self {
74 Self {
75 commit_info,
76 consensus_data_hash,
77 }
78 }
79
80 pub fn genesis(
83 genesis_state_root_hash: HashValue, validator_set: ValidatorSet,
84 ) -> Self {
85 Self::new(
86 BlockInfo::genesis(genesis_state_root_hash, validator_set),
87 HashValue::zero(),
88 )
89 }
90
91 #[cfg(any(test, feature = "fuzzing"))]
92 pub fn mock_genesis(validator_set: Option<ValidatorSet>) -> Self {
93 Self::new(BlockInfo::mock_genesis(validator_set), HashValue::zero())
94 }
95
96 pub fn commit_info(&self) -> &BlockInfo { &self.commit_info }
98
99 pub fn epoch(&self) -> u64 { self.commit_info.epoch() }
102
103 pub fn next_block_epoch(&self) -> u64 {
104 self.commit_info.next_block_epoch()
105 }
106
107 pub fn round(&self) -> Round { self.commit_info.round() }
108
109 pub fn consensus_block_id(&self) -> HashValue { self.commit_info.id() }
110
111 pub fn transaction_accumulator_hash(&self) -> HashValue {
112 self.commit_info.executed_state_id()
113 }
114
115 pub fn version(&self) -> Version { self.commit_info.version() }
116
117 pub fn timestamp_usecs(&self) -> u64 { self.commit_info.timestamp_usecs() }
118
119 pub fn next_epoch_state(&self) -> Option<&EpochState> {
120 self.commit_info.next_epoch_state()
121 }
122
123 pub fn ends_epoch(&self) -> bool { self.next_epoch_state().is_some() }
124
125 pub fn consensus_data_hash(&self) -> HashValue { self.consensus_data_hash }
127
128 pub fn pivot_decision(&self) -> Option<&PivotBlockDecision> {
129 self.commit_info.pivot_decision()
130 }
131
132 pub fn set_consensus_data_hash(&mut self, consensus_data_hash: HashValue) {
133 self.consensus_data_hash = consensus_data_hash;
134 }
135}
136
137#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
140pub enum LedgerInfoWithSignatures {
141 V0(LedgerInfoWithV0),
142}
143
144impl Display for LedgerInfoWithSignatures {
145 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
146 match self {
147 LedgerInfoWithSignatures::V0(ledger) => write!(f, "{}", ledger),
148 }
149 }
150}
151
152impl LedgerInfoWithSignatures {
154 pub fn new(
155 ledger_info: LedgerInfo,
156 signatures: BTreeMap<AccountAddress, ConsensusSignature>,
157 ) -> Self {
158 LedgerInfoWithSignatures::V0(LedgerInfoWithV0::new(
159 ledger_info,
160 signatures,
161 ))
162 }
163
164 pub fn genesis(
165 genesis_state_root_hash: HashValue, validator_set: ValidatorSet,
166 ) -> Self {
167 LedgerInfoWithSignatures::V0(LedgerInfoWithV0::genesis(
168 genesis_state_root_hash,
169 validator_set,
170 ))
171 }
172}
173
174impl Deref for LedgerInfoWithSignatures {
177 type Target = LedgerInfoWithV0;
178
179 fn deref(&self) -> &LedgerInfoWithV0 {
180 match &self {
181 LedgerInfoWithSignatures::V0(ledger) => ledger,
182 }
183 }
184}
185
186impl DerefMut for LedgerInfoWithSignatures {
187 fn deref_mut(&mut self) -> &mut LedgerInfoWithV0 {
188 match self {
189 LedgerInfoWithSignatures::V0(ref mut ledger) => ledger,
190 }
191 }
192}
193
194#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
200pub struct LedgerInfoWithV0 {
201 ledger_info: LedgerInfo,
202 signatures: BTreeMap<AccountAddress, ConsensusSignature>,
206}
207
208impl Display for LedgerInfoWithV0 {
209 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
210 write!(f, "{}", self.ledger_info)
211 }
212}
213
214impl LedgerInfoWithV0 {
215 pub fn new(
216 ledger_info: LedgerInfo,
217 signatures: BTreeMap<AccountAddress, ConsensusSignature>,
218 ) -> Self {
219 LedgerInfoWithV0 {
220 ledger_info,
221 signatures,
222 }
223 }
224
225 pub fn genesis(
234 genesis_state_root_hash: HashValue, validator_set: ValidatorSet,
235 ) -> Self {
236 Self::new(
237 LedgerInfo::genesis(genesis_state_root_hash, validator_set),
238 BTreeMap::new(),
239 )
240 }
241
242 pub fn ledger_info(&self) -> &LedgerInfo { &self.ledger_info }
243
244 pub fn add_signature(
245 &mut self, validator: AccountAddress, signature: ConsensusSignature,
246 ) {
247 self.signatures.entry(validator).or_insert(signature);
248 }
249
250 pub fn remove_signature(&mut self, validator: AccountAddress) {
251 self.signatures.remove(&validator);
252 }
253
254 pub fn signatures(&self) -> &BTreeMap<AccountAddress, ConsensusSignature> {
255 &self.signatures
256 }
257
258 pub fn verify_signatures(
259 &self, validator: &ValidatorVerifier,
260 ) -> ::std::result::Result<(), VerifyError> {
261 validator.batch_verify_aggregated_signatures(
262 self.ledger_info(),
263 self.signatures(),
264 )
265 }
266}
267
268#[derive(Deserialize)]
269pub struct LedgerInfoWithV0Unchecked {
270 pub ledger_info: LedgerInfo,
271 pub signatures: BTreeMap<AccountAddress, BLSSignatureUnchecked>,
275}
276
277impl From<LedgerInfoWithV0Unchecked> for LedgerInfoWithV0 {
278 fn from(unchecked: LedgerInfoWithV0Unchecked) -> Self {
279 Self::new(
280 unchecked.ledger_info,
281 unchecked
282 .signatures
283 .into_iter()
284 .map(|(k, v)| (k, v.into()))
285 .collect(),
286 )
287 }
288}
289
290#[derive(Deserialize)]
291pub enum LedgerInfoWithSignaturesUnchecked {
292 V0(LedgerInfoWithV0Unchecked),
293}
294
295impl From<LedgerInfoWithSignaturesUnchecked> for LedgerInfoWithSignatures {
296 fn from(unchecked: LedgerInfoWithSignaturesUnchecked) -> Self {
297 match unchecked {
298 LedgerInfoWithSignaturesUnchecked::V0(l) => Self::V0(l.into()),
299 }
300 }
301}
302
303pub fn deserialize_ledger_info_unchecked<'de, D>(
304 deserializer: D,
305) -> Result<LedgerInfoWithSignatures, D::Error>
306where D: Deserializer<'de> {
307 LedgerInfoWithSignaturesUnchecked::deserialize(deserializer).map(Into::into)
308}
309
310use crate::{
315 block_info::PivotBlockDecision, validator_config::ConsensusSignature,
316};
317#[cfg(any(test, feature = "fuzzing"))]
318use ::proptest::prelude::*;
319use diem_crypto::bls::BLSSignatureUnchecked;
320
321#[cfg(any(test, feature = "fuzzing"))]
322impl Arbitrary for LedgerInfoWithV0 {
323 type Parameters = ();
324 type Strategy = BoxedStrategy<Self>;
325
326 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
327 let dummy_signature = ConsensusSignature::dummy_signature();
328 (
329 proptest::arbitrary::any::<LedgerInfo>(),
330 proptest::collection::vec(
331 proptest::arbitrary::any::<AccountAddress>(),
332 0..100,
333 ),
334 )
335 .prop_map(move |(ledger_info, addresses)| {
336 let mut signatures = BTreeMap::new();
337 for address in addresses {
338 let signature = dummy_signature.clone();
339 signatures.insert(address, signature);
340 }
341 Self {
342 ledger_info,
343 signatures,
344 }
345 })
346 .boxed()
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353 use crate::validator_signer::ValidatorSigner;
354
355 #[test]
356 fn test_signatures_hash() {
357 let ledger_info =
358 LedgerInfo::new(BlockInfo::empty(), HashValue::random());
359
360 const NUM_SIGNERS: u8 = 7;
361 let validator_signers: Vec<ValidatorSigner> = (0..NUM_SIGNERS)
363 .map(|i| ValidatorSigner::random([i; 32]))
364 .collect();
365 let mut author_to_signature_map = BTreeMap::new();
366 for validator in validator_signers.iter() {
367 author_to_signature_map
368 .insert(validator.author(), validator.sign(&ledger_info));
369 }
370
371 let ledger_info_with_signatures =
372 LedgerInfoWithV0::new(ledger_info.clone(), author_to_signature_map);
373
374 let mut author_to_signature_map = BTreeMap::new();
377 for validator in validator_signers.iter().rev() {
378 author_to_signature_map
379 .insert(validator.author(), validator.sign(&ledger_info));
380 }
381
382 let ledger_info_with_signatures_reversed =
383 LedgerInfoWithV0::new(ledger_info, author_to_signature_map);
384
385 let ledger_info_with_signatures_bytes =
386 bcs::to_bytes(&ledger_info_with_signatures)
387 .expect("block serialization failed");
388 let ledger_info_with_signatures_reversed_bytes =
389 bcs::to_bytes(&ledger_info_with_signatures_reversed)
390 .expect("block serialization failed");
391
392 assert_eq!(
393 ledger_info_with_signatures_bytes,
394 ledger_info_with_signatures_reversed_bytes
395 );
396 }
397}