primitives/
block_header.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5mod base_price;
6pub use base_price::{
7    compute_next_price, compute_next_price_tuple, estimate_gas_used_boundary,
8    estimate_max_possible_gas,
9};
10
11use crate::{
12    block::BlockHeight, bytes::Bytes, hash::keccak, pos::PosBlockId,
13    receipt::BlockReceipts, MERKLE_NULL_NODE, NULL_EPOCH,
14};
15use cfx_parameters::block::{cspace_block_gas_limit, espace_block_gas_limit};
16use cfx_types::{
17    Address, Bloom, Space, SpaceMap, H256, KECCAK_EMPTY_BLOOM, U256,
18};
19use malloc_size_of::{new_malloc_size_ops, MallocSizeOf, MallocSizeOfOps};
20use once_cell::sync::OnceCell;
21use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
22use rlp_derive::{RlpDecodable, RlpEncodable};
23use std::{
24    mem,
25    ops::{Deref, DerefMut},
26    sync::Arc,
27};
28
29const HEADER_LIST_MIN_LEN: usize = 13;
30/// The height to start fixing the wrong encoding/decoding of the `custom`
31/// field.
32pub static CIP112_TRANSITION_HEIGHT: OnceCell<u64> = OnceCell::new();
33
34pub const BASE_PRICE_CHANGE_DENOMINATOR: usize = 8;
35
36#[derive(Clone, Debug, Eq)]
37pub struct BlockHeaderRlpPart {
38    /// Parent hash.
39    parent_hash: H256,
40    /// Block height
41    height: BlockHeight,
42    /// Block timestamp.
43    timestamp: u64,
44    /// Block author.
45    author: Address,
46    /// Transactions root.
47    transactions_root: H256,
48    /// Deferred state root.
49    deferred_state_root: H256,
50    /// Deferred block receipts root.
51    deferred_receipts_root: H256,
52    /// Deferred block logs bloom hash.
53    deferred_logs_bloom_hash: H256,
54    /// Blame indicates the number of ancestors whose
55    /// state_root/receipts_root/logs_bloom_hash/blame are not correct.
56    /// It acts as a vote to help light client determining the
57    /// state_root/receipts_root/logs_bloom_hash are correct or not.
58    blame: u32,
59    /// Block difficulty.
60    difficulty: U256,
61    /// Whether it is an adaptive block (from GHAST algorithm)
62    adaptive: bool,
63    /// Gas limit.
64    gas_limit: U256,
65    /// Referee hashes
66    referee_hashes: Vec<H256>,
67    /// Customized information
68    custom: Vec<Bytes>,
69    /// Nonce of the block
70    nonce: U256,
71    /// Referred PoS block ID.
72    pos_reference: Option<H256>,
73    /// `[core_space_base_price, espace_base_price]`.
74    base_price: Option<BasePrice>,
75}
76
77impl PartialEq for BlockHeaderRlpPart {
78    fn eq(&self, o: &BlockHeaderRlpPart) -> bool {
79        self.parent_hash == o.parent_hash
80            && self.height == o.height
81            && self.timestamp == o.timestamp
82            && self.author == o.author
83            && self.transactions_root == o.transactions_root
84            && self.deferred_state_root == o.deferred_state_root
85            && self.deferred_receipts_root == o.deferred_receipts_root
86            && self.deferred_logs_bloom_hash == o.deferred_logs_bloom_hash
87            && self.blame == o.blame
88            && self.difficulty == o.difficulty
89            && self.adaptive == o.adaptive
90            && self.gas_limit == o.gas_limit
91            && self.referee_hashes == o.referee_hashes
92            && self.custom == o.custom
93            && self.pos_reference == o.pos_reference
94            && self.base_price == o.base_price
95    }
96}
97
98/// A block header.
99#[derive(Clone, Debug, Eq)]
100pub struct BlockHeader {
101    rlp_part: BlockHeaderRlpPart,
102    /// Hash of the block
103    hash: Option<H256>,
104    /// POW quality of the block
105    pub pow_hash: Option<H256>,
106    /// Approximated rlp size of the block header
107    pub approximated_rlp_size: usize,
108}
109
110impl Deref for BlockHeader {
111    type Target = BlockHeaderRlpPart;
112
113    fn deref(&self) -> &Self::Target { &self.rlp_part }
114}
115
116impl DerefMut for BlockHeader {
117    fn deref_mut(&mut self) -> &mut BlockHeaderRlpPart { &mut self.rlp_part }
118}
119
120impl MallocSizeOf for BlockHeader {
121    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
122        self.referee_hashes.size_of(ops) + self.custom.size_of(ops)
123    }
124}
125
126impl PartialEq for BlockHeader {
127    fn eq(&self, o: &BlockHeader) -> bool { self.rlp_part == o.rlp_part }
128}
129
130impl BlockHeader {
131    /// Approximated rlp size of the block header.
132    pub fn approximated_rlp_size(&self) -> usize { self.approximated_rlp_size }
133
134    /// Get the parent_hash field of the header.
135    pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
136
137    /// Get the block height
138    pub fn height(&self) -> u64 { self.height }
139
140    /// Get the timestamp field of the header.
141    pub fn timestamp(&self) -> u64 { self.timestamp }
142
143    /// Get the author field of the header.
144    pub fn author(&self) -> &Address { &self.author }
145
146    /// Get the transactions root field of the header.
147    pub fn transactions_root(&self) -> &H256 { &self.transactions_root }
148
149    /// Get the deferred state root field of the header.
150    pub fn deferred_state_root(&self) -> &H256 { &self.deferred_state_root }
151
152    /// Get the deferred block receipts root field of the header.
153    pub fn deferred_receipts_root(&self) -> &H256 {
154        &self.deferred_receipts_root
155    }
156
157    /// Get the deferred block logs bloom hash field of the header.
158    pub fn deferred_logs_bloom_hash(&self) -> &H256 {
159        &self.deferred_logs_bloom_hash
160    }
161
162    /// Get the blame field of the header
163    pub fn blame(&self) -> u32 { self.blame }
164
165    /// Get the difficulty field of the header.
166    pub fn difficulty(&self) -> &U256 { &self.difficulty }
167
168    /// Get the adaptive field of the header
169    pub fn adaptive(&self) -> bool { self.adaptive }
170
171    /// Get the gas limit field of the header.
172    pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
173
174    pub fn core_space_gas_limit(&self) -> U256 {
175        cspace_block_gas_limit(
176            self.base_price.is_some(),
177            self.gas_limit().to_owned(),
178        )
179    }
180
181    pub fn espace_gas_limit(&self, can_pack: bool) -> U256 {
182        espace_block_gas_limit(can_pack, self.gas_limit().to_owned())
183    }
184
185    /// Get the referee hashes field of the header.
186    pub fn referee_hashes(&self) -> &Vec<H256> { &self.referee_hashes }
187
188    /// Get the custom data field of the header.
189    pub fn custom(&self) -> &Vec<Bytes> { &self.custom }
190
191    /// Get the nonce field of the header.
192    pub fn nonce(&self) -> U256 { self.nonce }
193
194    /// Get the PoS reference.
195    pub fn pos_reference(&self) -> &Option<PosBlockId> { &self.pos_reference }
196
197    pub fn base_price(&self) -> Option<SpaceMap<U256>> {
198        self.base_price.map(
199            |BasePrice {
200                 core_base_price,
201                 espace_base_price,
202             }| SpaceMap::new(core_base_price, espace_base_price),
203        )
204    }
205
206    // Get the base price for the given space after 1559 hardfork.
207    pub fn space_base_price(&self, space: Space) -> Option<U256> {
208        self.base_price.map(|x| match space {
209            Space::Native => x.core_base_price,
210            Space::Ethereum => x.espace_base_price,
211        })
212    }
213
214    /// Set the nonce field of the header.
215    pub fn set_nonce(&mut self, nonce: U256) { self.nonce = nonce; }
216
217    /// Set the timestamp filed of the header.
218    pub fn set_timestamp(&mut self, timestamp: u64) {
219        self.timestamp = timestamp;
220    }
221
222    /// Set the custom filed of the header.
223    pub fn set_custom(&mut self, custom: Vec<Bytes>) { self.custom = custom; }
224
225    /// Compute the hash of the block.
226    pub fn compute_hash(&mut self) -> H256 {
227        let hash = self.hash();
228        self.hash = Some(hash);
229        hash
230    }
231
232    /// Get the hash of the block.
233    pub fn hash(&self) -> H256 {
234        self.hash.unwrap_or_else(|| keccak(self.rlp()))
235    }
236
237    /// Get the hash of PoW problem.
238    pub fn problem_hash(&self) -> H256 { keccak(self.rlp_without_nonce()) }
239
240    /// Get the RLP representation of this header(except nonce).
241    pub fn rlp_without_nonce(&self) -> Bytes {
242        let mut stream = RlpStream::new();
243        self.stream_rlp_without_nonce(&mut stream);
244        stream.out().to_vec()
245    }
246
247    /// Get the RLP representation of this header.
248    pub fn rlp(&self) -> Bytes {
249        let mut stream = RlpStream::new();
250        self.stream_rlp(&mut stream);
251        stream.out().to_vec()
252    }
253
254    /// Place this header(except nonce) into an RLP stream `stream`.
255    fn stream_rlp_without_nonce(&self, stream: &mut RlpStream) {
256        let adaptive_n = if self.adaptive { 1_u8 } else { 0_u8 };
257        let list_len = HEADER_LIST_MIN_LEN
258            + self.pos_reference.is_some() as usize
259            + self.base_price.is_some() as usize
260            + self.custom.len();
261        stream
262            .begin_list(list_len)
263            .append(&self.parent_hash)
264            .append(&self.height)
265            .append(&self.timestamp)
266            .append(&self.author)
267            .append(&self.transactions_root)
268            .append(&self.deferred_state_root)
269            .append(&self.deferred_receipts_root)
270            .append(&self.deferred_logs_bloom_hash)
271            .append(&self.blame)
272            .append(&self.difficulty)
273            .append(&adaptive_n)
274            .append(&self.gas_limit)
275            .append_list(&self.referee_hashes);
276        if self.pos_reference.is_some() {
277            stream.append(&self.pos_reference);
278        }
279        if self.base_price.is_some() {
280            stream.append(&self.base_price);
281        }
282
283        for b in &self.custom {
284            if self.height
285                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
286            {
287                stream.append(b);
288            } else {
289                stream.append_raw(b, 1);
290            }
291        }
292    }
293
294    /// Place this header into an RLP stream `stream`.
295    fn stream_rlp(&self, stream: &mut RlpStream) {
296        let adaptive_n = if self.adaptive { 1_u8 } else { 0_u8 };
297        let list_len = HEADER_LIST_MIN_LEN
298            + 1
299            + self.pos_reference.is_some() as usize
300            + self.base_price.is_some() as usize
301            + self.custom.len();
302        stream
303            .begin_list(list_len)
304            .append(&self.parent_hash)
305            .append(&self.height)
306            .append(&self.timestamp)
307            .append(&self.author)
308            .append(&self.transactions_root)
309            .append(&self.deferred_state_root)
310            .append(&self.deferred_receipts_root)
311            .append(&self.deferred_logs_bloom_hash)
312            .append(&self.blame)
313            .append(&self.difficulty)
314            .append(&adaptive_n)
315            .append(&self.gas_limit)
316            .append_list(&self.referee_hashes)
317            .append(&self.nonce);
318        if self.pos_reference.is_some() {
319            stream.append(&self.pos_reference);
320        }
321        if self.base_price.is_some() {
322            stream.append(&self.base_price);
323        }
324        for b in &self.custom {
325            if self.height
326                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
327            {
328                stream.append(b);
329            } else {
330                stream.append_raw(b, 1);
331            }
332        }
333    }
334
335    /// Place this header and its `pow_hash` into an RLP stream `stream`.
336    pub fn stream_rlp_with_pow_hash(&self, stream: &mut RlpStream) {
337        let adaptive_n = if self.adaptive { 1_u8 } else { 0_u8 };
338        let list_len = HEADER_LIST_MIN_LEN
339            + 2
340            + self.pos_reference.is_some() as usize
341            + self.base_price.is_some() as usize
342            + self.custom.len();
343        stream
344            .begin_list(list_len)
345            .append(&self.parent_hash)
346            .append(&self.height)
347            .append(&self.timestamp)
348            .append(&self.author)
349            .append(&self.transactions_root)
350            .append(&self.deferred_state_root)
351            .append(&self.deferred_receipts_root)
352            .append(&self.deferred_logs_bloom_hash)
353            .append(&self.blame)
354            .append(&self.difficulty)
355            .append(&adaptive_n)
356            .append(&self.gas_limit)
357            .append_list(&self.referee_hashes)
358            .append(&self.nonce)
359            // Just encode the Option for future compatibility.
360            // It should always be Some when it is being inserted to db.
361            .append(&self.pow_hash);
362        if self.pos_reference.is_some() {
363            stream.append(&self.pos_reference);
364        }
365        if self.base_price.is_some() {
366            stream.append(&self.base_price);
367        }
368
369        for b in &self.custom {
370            if self.height
371                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
372            {
373                stream.append(b);
374            } else {
375                stream.append_raw(b, 1);
376            }
377        }
378    }
379
380    pub fn decode_with_pow_hash(bytes: &[u8]) -> Result<Self, DecoderError> {
381        let r = Rlp::new(bytes);
382        let mut rlp_part = BlockHeaderRlpPart {
383            parent_hash: r.val_at(0)?,
384            height: r.val_at(1)?,
385            timestamp: r.val_at(2)?,
386            author: r.val_at(3)?,
387            transactions_root: r.val_at(4)?,
388            deferred_state_root: r.val_at(5)?,
389            deferred_receipts_root: r.val_at(6)?,
390            deferred_logs_bloom_hash: r.val_at(7)?,
391            blame: r.val_at(8)?,
392            difficulty: r.val_at(9)?,
393            adaptive: r.val_at::<u8>(10)? == 1,
394            gas_limit: r.val_at(11)?,
395            referee_hashes: r.list_at(12)?,
396            custom: vec![],
397            nonce: r.val_at(13)?,
398            pos_reference: r.val_at(15).unwrap_or(None),
399            base_price: r.val_at(16).unwrap_or(None),
400        };
401        let pow_hash = r.val_at(14)?;
402
403        for i in (15
404            + rlp_part.pos_reference.is_some() as usize
405            + rlp_part.base_price.is_some() as usize)
406            ..r.item_count()?
407        {
408            if rlp_part.height
409                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
410            {
411                rlp_part.custom.push(r.val_at(i)?);
412            } else {
413                rlp_part.custom.push(r.at(i)?.as_raw().to_vec());
414            }
415        }
416
417        let mut header = BlockHeader {
418            rlp_part,
419            hash: None,
420            pow_hash,
421            approximated_rlp_size: bytes.len(),
422        };
423        header.compute_hash();
424        Ok(header)
425    }
426
427    pub fn size(&self) -> usize {
428        // FIXME: We need to revisit the size of block header once we finished
429        // the persistent storage part
430        0
431    }
432}
433
434pub struct BlockHeaderBuilder {
435    parent_hash: H256,
436    height: u64,
437    timestamp: u64,
438    author: Address,
439    transactions_root: H256,
440    deferred_state_root: H256,
441    deferred_receipts_root: H256,
442    deferred_logs_bloom_hash: H256,
443    blame: u32,
444    difficulty: U256,
445    adaptive: bool,
446    gas_limit: U256,
447    referee_hashes: Vec<H256>,
448    custom: Vec<Bytes>,
449    nonce: U256,
450    pos_reference: Option<PosBlockId>,
451    base_price: Option<BasePrice>,
452}
453
454impl Default for BlockHeaderBuilder {
455    fn default() -> Self { Self::new() }
456}
457
458impl BlockHeaderBuilder {
459    pub fn new() -> Self {
460        Self {
461            parent_hash: NULL_EPOCH,
462            height: 0,
463            timestamp: 0,
464            author: Address::default(),
465            transactions_root: MERKLE_NULL_NODE,
466            deferred_state_root: Default::default(),
467            deferred_receipts_root: Default::default(),
468            deferred_logs_bloom_hash: KECCAK_EMPTY_BLOOM,
469            blame: 0,
470            difficulty: U256::default(),
471            adaptive: false,
472            gas_limit: U256::zero(),
473            referee_hashes: Vec::new(),
474            custom: Vec::new(),
475            nonce: U256::zero(),
476            pos_reference: None,
477            base_price: None,
478        }
479    }
480
481    pub fn with_parent_hash(&mut self, parent_hash: H256) -> &mut Self {
482        self.parent_hash = parent_hash;
483        self
484    }
485
486    pub fn with_height(&mut self, height: u64) -> &mut Self {
487        self.height = height;
488        self
489    }
490
491    pub fn with_timestamp(&mut self, timestamp: u64) -> &mut Self {
492        self.timestamp = timestamp;
493        self
494    }
495
496    pub fn with_author(&mut self, author: Address) -> &mut Self {
497        self.author = author;
498        self
499    }
500
501    pub fn with_transactions_root(
502        &mut self, transactions_root: H256,
503    ) -> &mut Self {
504        self.transactions_root = transactions_root;
505        self
506    }
507
508    pub fn with_deferred_state_root(
509        &mut self, deferred_state_root: H256,
510    ) -> &mut Self {
511        self.deferred_state_root = deferred_state_root;
512        self
513    }
514
515    pub fn with_deferred_receipts_root(
516        &mut self, deferred_receipts_root: H256,
517    ) -> &mut Self {
518        self.deferred_receipts_root = deferred_receipts_root;
519        self
520    }
521
522    pub fn with_deferred_logs_bloom_hash(
523        &mut self, deferred_logs_bloom_hash: H256,
524    ) -> &mut Self {
525        self.deferred_logs_bloom_hash = deferred_logs_bloom_hash;
526        self
527    }
528
529    pub fn with_blame(&mut self, blame: u32) -> &mut Self {
530        self.blame = blame;
531        self
532    }
533
534    pub fn with_difficulty(&mut self, difficulty: U256) -> &mut Self {
535        self.difficulty = difficulty;
536        self
537    }
538
539    pub fn with_adaptive(&mut self, adaptive: bool) -> &mut Self {
540        self.adaptive = adaptive;
541        self
542    }
543
544    pub fn with_gas_limit(&mut self, gas_limit: U256) -> &mut Self {
545        self.gas_limit = gas_limit;
546        self
547    }
548
549    pub fn with_referee_hashes(
550        &mut self, referee_hashes: Vec<H256>,
551    ) -> &mut Self {
552        self.referee_hashes = referee_hashes;
553        self
554    }
555
556    pub fn with_custom(&mut self, custom: Vec<Bytes>) -> &mut Self {
557        self.custom = custom;
558        self
559    }
560
561    pub fn with_nonce(&mut self, nonce: U256) -> &mut Self {
562        self.nonce = nonce;
563        self
564    }
565
566    pub fn with_pos_reference(
567        &mut self, pos_reference: Option<PosBlockId>,
568    ) -> &mut Self {
569        self.pos_reference = pos_reference;
570        self
571    }
572
573    pub fn with_base_price(
574        &mut self, maybe_base_price: Option<SpaceMap<U256>>,
575    ) -> &mut Self {
576        self.base_price = maybe_base_price.map(|x| BasePrice {
577            core_base_price: x[Space::Native],
578            espace_base_price: x[Space::Ethereum],
579        });
580        self
581    }
582
583    pub fn build(&self) -> BlockHeader {
584        let mut block_header = BlockHeader {
585            rlp_part: BlockHeaderRlpPart {
586                parent_hash: self.parent_hash,
587                height: self.height,
588                timestamp: self.timestamp,
589                author: self.author,
590                transactions_root: self.transactions_root,
591                deferred_state_root: self.deferred_state_root,
592                deferred_receipts_root: self.deferred_receipts_root,
593                deferred_logs_bloom_hash: self.deferred_logs_bloom_hash,
594                blame: self.blame,
595                difficulty: self.difficulty,
596                adaptive: self.adaptive,
597                gas_limit: self.gas_limit,
598                referee_hashes: self.referee_hashes.clone(),
599                custom: self.custom.clone(),
600                nonce: self.nonce,
601                pos_reference: self.pos_reference,
602                base_price: self.base_price,
603            },
604            hash: None,
605            pow_hash: None,
606            approximated_rlp_size: 0,
607        };
608
609        block_header.approximated_rlp_size =
610            mem::size_of::<BlockHeaderRlpPart>()
611                + block_header
612                    .referee_hashes
613                    .size_of(&mut new_malloc_size_ops());
614
615        block_header
616    }
617
618    pub fn compute_block_logs_bloom_hash(
619        receipts: &[Arc<BlockReceipts>],
620    ) -> H256 {
621        let bloom = receipts.iter().flat_map(|x| &x.receipts).fold(
622            Bloom::zero(),
623            |mut b, r| {
624                b.accrue_bloom(&r.log_bloom);
625                b
626            },
627        );
628
629        keccak(bloom)
630    }
631
632    pub fn compute_aggregated_bloom(blooms: Vec<Bloom>) -> Bloom {
633        blooms.into_iter().fold(Bloom::zero(), |mut res, bloom| {
634            res.accrue_bloom(&bloom);
635            res
636        })
637    }
638
639    pub fn compute_blame_state_root_vec_root(roots: Vec<H256>) -> H256 {
640        let mut accumulated_root = *roots.last().unwrap();
641        for i in (0..(roots.len() - 1)).rev() {
642            accumulated_root =
643                BlockHeaderBuilder::compute_blame_state_root_incremental(
644                    roots[i],
645                    accumulated_root,
646                );
647        }
648        accumulated_root
649    }
650
651    pub fn compute_blame_state_root_incremental(
652        first_root: H256, remaining_root: H256,
653    ) -> H256 {
654        let mut buffer = Vec::with_capacity(H256::len_bytes() * 2);
655        buffer.extend_from_slice(first_root.as_bytes());
656        buffer.extend_from_slice(remaining_root.as_bytes());
657        keccak(&buffer)
658    }
659}
660
661impl Encodable for BlockHeader {
662    fn rlp_append(&self, stream: &mut RlpStream) { self.stream_rlp(stream); }
663}
664
665impl Decodable for BlockHeader {
666    fn decode(r: &Rlp) -> Result<Self, DecoderError> {
667        let rlp_size = r.as_raw().len();
668        let mut rlp_part = BlockHeaderRlpPart {
669            parent_hash: r.val_at(0)?,
670            height: r.val_at(1)?,
671            timestamp: r.val_at(2)?,
672            author: r.val_at(3)?,
673            transactions_root: r.val_at(4)?,
674            deferred_state_root: r.val_at(5)?,
675            deferred_receipts_root: r.val_at(6)?,
676            deferred_logs_bloom_hash: r.val_at(7)?,
677            blame: r.val_at(8)?,
678            difficulty: r.val_at(9)?,
679            adaptive: r.val_at::<u8>(10)? == 1,
680            gas_limit: r.val_at(11)?,
681            referee_hashes: r.list_at(12)?,
682            custom: vec![],
683            nonce: r.val_at(13)?,
684            pos_reference: r.val_at(14).unwrap_or(None),
685            base_price: r.val_at(15).unwrap_or(None),
686        };
687        for i in (14
688            + rlp_part.pos_reference.is_some() as usize
689            + rlp_part.base_price.is_some() as usize)
690            ..r.item_count()?
691        {
692            if rlp_part.height
693                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
694            {
695                rlp_part.custom.push(r.val_at(i)?);
696            } else {
697                rlp_part.custom.push(r.at(i)?.as_raw().to_vec());
698            }
699        }
700
701        let mut header = BlockHeader {
702            rlp_part,
703            hash: None,
704            pow_hash: None,
705            approximated_rlp_size: rlp_size,
706        };
707        header.compute_hash();
708
709        Ok(header)
710    }
711}
712
713#[derive(Clone, Copy, Debug, Eq, RlpDecodable, RlpEncodable, PartialEq)]
714pub struct BasePrice {
715    pub core_base_price: U256,
716    pub espace_base_price: U256,
717}
718#[cfg(test)]
719mod tests {
720    use super::BlockHeaderBuilder;
721    use crate::{
722        hash::keccak,
723        receipt::{BlockReceipts, Receipt},
724        TransactionStatus,
725    };
726    use cfx_types::{Bloom, KECCAK_EMPTY_BLOOM, U256};
727    use std::{str::FromStr, sync::Arc};
728
729    #[test]
730    fn test_logs_bloom_hash_no_receipts() {
731        let receipts = vec![]; // Vec<_>
732        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
733        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
734
735        let receipts: Vec<Arc<BlockReceipts>> = (1..11)
736            .map(|_| {
737                Arc::new(BlockReceipts {
738                    receipts: vec![],
739                    block_number: 0,
740                    secondary_reward: U256::zero(),
741                    tx_execution_error_messages: vec![],
742                })
743            })
744            .collect();
745        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
746        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
747    }
748
749    #[test]
750    fn test_logs_bloom_hash_empty_receipts() {
751        let receipt = Receipt {
752            accumulated_gas_used: U256::zero(),
753            gas_fee: U256::zero(),
754            gas_sponsor_paid: false,
755            logs: vec![],
756            outcome_status: TransactionStatus::Success,
757            log_bloom: Bloom::zero(),
758            storage_sponsor_paid: false,
759            storage_collateralized: vec![],
760            storage_released: vec![],
761            burnt_gas_fee: None,
762        };
763
764        // 10 blocks with 10 empty receipts each
765        let receipts: Vec<Arc<BlockReceipts>> = (1..11)
766            .map(|_| {
767                Arc::new(BlockReceipts {
768                    receipts: (1..11).map(|_| receipt.clone()).collect(),
769                    block_number: 0,
770                    secondary_reward: U256::zero(),
771                    tx_execution_error_messages: vec!["".into(); 10],
772                })
773            })
774            .collect();
775        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
776        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
777    }
778
779    #[test]
780    fn test_logs_bloom_hash() {
781        let block1 = BlockReceipts {
782            receipts: vec![
783                Receipt {
784                    accumulated_gas_used: 0.into(),
785                    gas_fee: 0.into(),
786                    gas_sponsor_paid: false,
787                    logs: vec![],
788                    outcome_status: TransactionStatus::Success,
789                    log_bloom: Bloom::from_str(
790                        "11111111111111111111111111111111\
791                         00000000000000000000000000000000\
792                         00000000000000000000000000000000\
793                         00000000000000000000000000000000\
794                         00000000000000000000000000000000\
795                         00000000000000000000000000000000\
796                         00000000000000000000000000000000\
797                         00000000000000000000000000000000\
798                         00000000000000000000000000000000\
799                         00000000000000000000000000000000\
800                         00000000000000000000000000000000\
801                         00000000000000000000000000000000\
802                         00000000000000000000000000000000\
803                         00000000000000000000000000000000\
804                         00000000000000000000000000000000\
805                         00000000000000000000000000000000",
806                    )
807                    .unwrap(),
808                    storage_sponsor_paid: false,
809                    storage_collateralized: vec![],
810                    storage_released: vec![],
811                    burnt_gas_fee: None,
812                },
813                Receipt {
814                    accumulated_gas_used: U256::zero(),
815                    gas_fee: U256::zero(),
816                    gas_sponsor_paid: false,
817                    logs: vec![],
818                    outcome_status: TransactionStatus::Success,
819                    log_bloom: Bloom::from_str(
820                        "00000000000000000000000000000000\
821                         22222222222222222222222222222222\
822                         00000000000000000000000000000000\
823                         00000000000000000000000000000000\
824                         00000000000000000000000000000000\
825                         00000000000000000000000000000000\
826                         00000000000000000000000000000000\
827                         00000000000000000000000000000000\
828                         00000000000000000000000000000000\
829                         00000000000000000000000000000000\
830                         00000000000000000000000000000000\
831                         00000000000000000000000000000000\
832                         00000000000000000000000000000000\
833                         00000000000000000000000000000000\
834                         00000000000000000000000000000000\
835                         00000000000000000000000000000000",
836                    )
837                    .unwrap(),
838                    storage_sponsor_paid: false,
839                    storage_collateralized: vec![],
840                    storage_released: vec![],
841                    burnt_gas_fee: None,
842                },
843            ],
844            block_number: 0,
845            secondary_reward: U256::zero(),
846            tx_execution_error_messages: vec!["".into(); 2],
847        };
848
849        let block2 = BlockReceipts {
850            receipts: vec![Receipt {
851                accumulated_gas_used: U256::zero(),
852                gas_fee: U256::zero(),
853                gas_sponsor_paid: false,
854                logs: vec![],
855                outcome_status: TransactionStatus::Success,
856                log_bloom: Bloom::from_str(
857                    "44444444444444440000000000000000\
858                     44444444444444440000000000000000\
859                     44444444444444440000000000000000\
860                     44444444444444440000000000000000\
861                     00000000000000000000000000000000\
862                     00000000000000000000000000000000\
863                     00000000000000000000000000000000\
864                     00000000000000000000000000000000\
865                     00000000000000000000000000000000\
866                     00000000000000000000000000000000\
867                     00000000000000000000000000000000\
868                     00000000000000000000000000000000\
869                     00000000000000000000000000000000\
870                     00000000000000000000000000000000\
871                     00000000000000000000000000000000\
872                     00000000000000000000000000000000",
873                )
874                .unwrap(),
875                storage_sponsor_paid: false,
876                storage_collateralized: vec![],
877                storage_released: vec![],
878                burnt_gas_fee: None,
879            }],
880            block_number: 0,
881            secondary_reward: U256::zero(),
882            tx_execution_error_messages: vec!["".into()],
883        };
884
885        let expected = keccak(
886            "55555555555555551111111111111111\
887             66666666666666662222222222222222\
888             44444444444444440000000000000000\
889             44444444444444440000000000000000\
890             00000000000000000000000000000000\
891             00000000000000000000000000000000\
892             00000000000000000000000000000000\
893             00000000000000000000000000000000\
894             00000000000000000000000000000000\
895             00000000000000000000000000000000\
896             00000000000000000000000000000000\
897             00000000000000000000000000000000\
898             00000000000000000000000000000000\
899             00000000000000000000000000000000\
900             00000000000000000000000000000000\
901             00000000000000000000000000000000"
902                .parse::<Bloom>()
903                .unwrap(),
904        );
905
906        let receipts = vec![Arc::new(block1), Arc::new(block2)];
907        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
908        assert_eq!(hash, expected);
909    }
910}