1use crate::{
5 account_address::AccountAddress,
6 block_info::{BlockInfo, Round},
7 epoch_state::EpochState,
8 on_chain_config::ValidatorSet,
9 transaction::Version,
10 validator_verifier::{ValidatorVerifier, VerifyError},
11};
12use diem_crypto::{ed25519::Ed25519Signature, hash::HashValue};
13use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
14#[cfg(any(test, feature = "fuzzing"))]
15use proptest_derive::Arbitrary;
16use serde::{Deserialize, Serialize};
17use std::{
18 collections::BTreeMap,
19 fmt::{Display, Formatter},
20 ops::{Deref, DerefMut},
21};
22
23#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, CryptoHasher, BCSCryptoHash)]
41#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
42pub struct LedgerInfo {
43 commit_info: BlockInfo,
44
45 consensus_data_hash: HashValue,
48}
49
50impl Display for LedgerInfo {
51 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
52 write!(f, "LedgerInfo: [commit_info: {}]", self.commit_info())
53 }
54}
55
56impl LedgerInfo {
57 pub fn new(commit_info: BlockInfo, consensus_data_hash: HashValue) -> Self {
59 Self {
60 commit_info,
61 consensus_data_hash,
62 }
63 }
64
65 pub fn genesis(genesis_state_root_hash: HashValue, validator_set: ValidatorSet) -> Self {
68 Self::new(
69 BlockInfo::genesis(genesis_state_root_hash, validator_set),
70 HashValue::zero(),
71 )
72 }
73
74 #[cfg(any(test, feature = "fuzzing"))]
75 pub fn mock_genesis(validator_set: Option<ValidatorSet>) -> Self {
76 Self::new(BlockInfo::mock_genesis(validator_set), HashValue::zero())
77 }
78
79 pub fn commit_info(&self) -> &BlockInfo {
81 &self.commit_info
82 }
83
84 pub fn epoch(&self) -> u64 {
87 self.commit_info.epoch()
88 }
89
90 pub fn next_block_epoch(&self) -> u64 {
91 self.commit_info.next_block_epoch()
92 }
93
94 pub fn round(&self) -> Round {
95 self.commit_info.round()
96 }
97
98 pub fn consensus_block_id(&self) -> HashValue {
99 self.commit_info.id()
100 }
101
102 pub fn transaction_accumulator_hash(&self) -> HashValue {
103 self.commit_info.executed_state_id()
104 }
105
106 pub fn version(&self) -> Version {
107 self.commit_info.version()
108 }
109
110 pub fn timestamp_usecs(&self) -> u64 {
111 self.commit_info.timestamp_usecs()
112 }
113
114 pub fn next_epoch_state(&self) -> Option<&EpochState> {
115 self.commit_info.next_epoch_state()
116 }
117
118 pub fn ends_epoch(&self) -> bool {
119 self.next_epoch_state().is_some()
120 }
121
122 pub fn consensus_data_hash(&self) -> HashValue {
124 self.consensus_data_hash
125 }
126
127 pub fn set_consensus_data_hash(&mut self, consensus_data_hash: HashValue) {
128 self.consensus_data_hash = consensus_data_hash;
129 }
130}
131
132#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
134pub enum LedgerInfoWithSignatures {
135 V0(LedgerInfoWithV0),
136}
137
138impl Display for LedgerInfoWithSignatures {
139 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
140 match self {
141 LedgerInfoWithSignatures::V0(ledger) => write!(f, "{}", ledger),
142 }
143 }
144}
145
146impl LedgerInfoWithSignatures {
148 pub fn new(
149 ledger_info: LedgerInfo,
150 signatures: BTreeMap<AccountAddress, Ed25519Signature>,
151 ) -> Self {
152 LedgerInfoWithSignatures::V0(LedgerInfoWithV0::new(ledger_info, signatures))
153 }
154
155 pub fn genesis(genesis_state_root_hash: HashValue, validator_set: ValidatorSet) -> Self {
156 LedgerInfoWithSignatures::V0(LedgerInfoWithV0::genesis(
157 genesis_state_root_hash,
158 validator_set,
159 ))
160 }
161}
162
163impl Deref for LedgerInfoWithSignatures {
166 type Target = LedgerInfoWithV0;
167
168 fn deref(&self) -> &LedgerInfoWithV0 {
169 match &self {
170 LedgerInfoWithSignatures::V0(ledger) => ledger,
171 }
172 }
173}
174
175impl DerefMut for LedgerInfoWithSignatures {
176 fn deref_mut(&mut self) -> &mut LedgerInfoWithV0 {
177 match self {
178 LedgerInfoWithSignatures::V0(ref mut ledger) => ledger,
179 }
180 }
181}
182
183#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
189pub struct LedgerInfoWithV0 {
190 ledger_info: LedgerInfo,
191 signatures: BTreeMap<AccountAddress, Ed25519Signature>,
194}
195
196impl Display for LedgerInfoWithV0 {
197 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
198 write!(f, "{}", self.ledger_info)
199 }
200}
201
202impl LedgerInfoWithV0 {
203 pub fn new(
204 ledger_info: LedgerInfo,
205 signatures: BTreeMap<AccountAddress, Ed25519Signature>,
206 ) -> Self {
207 LedgerInfoWithV0 {
208 ledger_info,
209 signatures,
210 }
211 }
212
213 pub fn genesis(genesis_state_root_hash: HashValue, validator_set: ValidatorSet) -> Self {
221 Self::new(
222 LedgerInfo::genesis(genesis_state_root_hash, validator_set),
223 BTreeMap::new(),
224 )
225 }
226
227 pub fn ledger_info(&self) -> &LedgerInfo {
228 &self.ledger_info
229 }
230
231 pub fn commit_info(&self) -> &BlockInfo {
232 self.ledger_info.commit_info()
233 }
234
235 pub fn add_signature(&mut self, validator: AccountAddress, signature: Ed25519Signature) {
236 self.signatures.entry(validator).or_insert(signature);
237 }
238
239 pub fn remove_signature(&mut self, validator: AccountAddress) {
240 self.signatures.remove(&validator);
241 }
242
243 pub fn signatures(&self) -> &BTreeMap<AccountAddress, Ed25519Signature> {
244 &self.signatures
245 }
246
247 pub fn verify_signatures(
248 &self,
249 validator: &ValidatorVerifier,
250 ) -> ::std::result::Result<(), VerifyError> {
251 validator.batch_verify_aggregated_signatures(self.ledger_info(), self.signatures())
252 }
253
254 pub fn check_voting_power(
255 &self,
256 validator: &ValidatorVerifier,
257 ) -> ::std::result::Result<(), VerifyError> {
258 validator.check_voting_power(self.signatures.keys())
259 }
260}
261
262#[cfg(any(test, feature = "fuzzing"))]
267use ::proptest::prelude::*;
268
269#[cfg(any(test, feature = "fuzzing"))]
270impl Arbitrary for LedgerInfoWithV0 {
271 type Parameters = ();
272 type Strategy = BoxedStrategy<Self>;
273
274 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
275 let dummy_signature = Ed25519Signature::dummy_signature();
276 (
277 proptest::arbitrary::any::<LedgerInfo>(),
278 proptest::collection::vec(proptest::arbitrary::any::<AccountAddress>(), 0..100),
279 )
280 .prop_map(move |(ledger_info, addresses)| {
281 let mut signatures = BTreeMap::new();
282 for address in addresses {
283 let signature = dummy_signature.clone();
284 signatures.insert(address, signature);
285 }
286 Self {
287 ledger_info,
288 signatures,
289 }
290 })
291 .boxed()
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298 use crate::validator_signer::ValidatorSigner;
299
300 #[test]
301 fn test_signatures_hash() {
302 let ledger_info = LedgerInfo::new(BlockInfo::empty(), HashValue::random());
303
304 const NUM_SIGNERS: u8 = 7;
305 let validator_signers: Vec<ValidatorSigner> = (0..NUM_SIGNERS)
307 .map(|i| ValidatorSigner::random([i; 32]))
308 .collect();
309 let mut author_to_signature_map = BTreeMap::new();
310 for validator in validator_signers.iter() {
311 author_to_signature_map.insert(validator.author(), validator.sign(&ledger_info));
312 }
313
314 let ledger_info_with_signatures =
315 LedgerInfoWithV0::new(ledger_info.clone(), author_to_signature_map);
316
317 let mut author_to_signature_map = BTreeMap::new();
319 for validator in validator_signers.iter().rev() {
320 author_to_signature_map.insert(validator.author(), validator.sign(&ledger_info));
321 }
322
323 let ledger_info_with_signatures_reversed =
324 LedgerInfoWithV0::new(ledger_info, author_to_signature_map);
325
326 let ledger_info_with_signatures_bytes =
327 bcs::to_bytes(&ledger_info_with_signatures).expect("block serialization failed");
328 let ledger_info_with_signatures_reversed_bytes =
329 bcs::to_bytes(&ledger_info_with_signatures_reversed)
330 .expect("block serialization failed");
331
332 assert_eq!(
333 ledger_info_with_signatures_bytes,
334 ledger_info_with_signatures_reversed_bytes
335 );
336 }
337}