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()
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()
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 as u8 } else { 0 as 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 as u8 } else { 0 as 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 as u8 } else { 0 as 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 BlockHeaderBuilder {
455    pub fn new() -> Self {
456        Self {
457            parent_hash: NULL_EPOCH,
458            height: 0,
459            timestamp: 0,
460            author: Address::default(),
461            transactions_root: MERKLE_NULL_NODE,
462            deferred_state_root: Default::default(),
463            deferred_receipts_root: Default::default(),
464            deferred_logs_bloom_hash: KECCAK_EMPTY_BLOOM,
465            blame: 0,
466            difficulty: U256::default(),
467            adaptive: false,
468            gas_limit: U256::zero(),
469            referee_hashes: Vec::new(),
470            custom: Vec::new(),
471            nonce: U256::zero(),
472            pos_reference: None,
473            base_price: None,
474        }
475    }
476
477    pub fn with_parent_hash(&mut self, parent_hash: H256) -> &mut Self {
478        self.parent_hash = parent_hash;
479        self
480    }
481
482    pub fn with_height(&mut self, height: u64) -> &mut Self {
483        self.height = height;
484        self
485    }
486
487    pub fn with_timestamp(&mut self, timestamp: u64) -> &mut Self {
488        self.timestamp = timestamp;
489        self
490    }
491
492    pub fn with_author(&mut self, author: Address) -> &mut Self {
493        self.author = author;
494        self
495    }
496
497    pub fn with_transactions_root(
498        &mut self, transactions_root: H256,
499    ) -> &mut Self {
500        self.transactions_root = transactions_root;
501        self
502    }
503
504    pub fn with_deferred_state_root(
505        &mut self, deferred_state_root: H256,
506    ) -> &mut Self {
507        self.deferred_state_root = deferred_state_root;
508        self
509    }
510
511    pub fn with_deferred_receipts_root(
512        &mut self, deferred_receipts_root: H256,
513    ) -> &mut Self {
514        self.deferred_receipts_root = deferred_receipts_root;
515        self
516    }
517
518    pub fn with_deferred_logs_bloom_hash(
519        &mut self, deferred_logs_bloom_hash: H256,
520    ) -> &mut Self {
521        self.deferred_logs_bloom_hash = deferred_logs_bloom_hash;
522        self
523    }
524
525    pub fn with_blame(&mut self, blame: u32) -> &mut Self {
526        self.blame = blame;
527        self
528    }
529
530    pub fn with_difficulty(&mut self, difficulty: U256) -> &mut Self {
531        self.difficulty = difficulty;
532        self
533    }
534
535    pub fn with_adaptive(&mut self, adaptive: bool) -> &mut Self {
536        self.adaptive = adaptive;
537        self
538    }
539
540    pub fn with_gas_limit(&mut self, gas_limit: U256) -> &mut Self {
541        self.gas_limit = gas_limit;
542        self
543    }
544
545    pub fn with_referee_hashes(
546        &mut self, referee_hashes: Vec<H256>,
547    ) -> &mut Self {
548        self.referee_hashes = referee_hashes;
549        self
550    }
551
552    pub fn with_custom(&mut self, custom: Vec<Bytes>) -> &mut Self {
553        self.custom = custom;
554        self
555    }
556
557    pub fn with_nonce(&mut self, nonce: U256) -> &mut Self {
558        self.nonce = nonce;
559        self
560    }
561
562    pub fn with_pos_reference(
563        &mut self, pos_reference: Option<PosBlockId>,
564    ) -> &mut Self {
565        self.pos_reference = pos_reference;
566        self
567    }
568
569    pub fn with_base_price(
570        &mut self, maybe_base_price: Option<SpaceMap<U256>>,
571    ) -> &mut Self {
572        self.base_price = maybe_base_price.map(|x| BasePrice {
573            core_base_price: x[Space::Native],
574            espace_base_price: x[Space::Ethereum],
575        });
576        self
577    }
578
579    pub fn build(&self) -> BlockHeader {
580        let mut block_header = BlockHeader {
581            rlp_part: BlockHeaderRlpPart {
582                parent_hash: self.parent_hash,
583                height: self.height,
584                timestamp: self.timestamp,
585                author: self.author,
586                transactions_root: self.transactions_root,
587                deferred_state_root: self.deferred_state_root,
588                deferred_receipts_root: self.deferred_receipts_root,
589                deferred_logs_bloom_hash: self.deferred_logs_bloom_hash,
590                blame: self.blame,
591                difficulty: self.difficulty,
592                adaptive: self.adaptive,
593                gas_limit: self.gas_limit,
594                referee_hashes: self.referee_hashes.clone(),
595                custom: self.custom.clone(),
596                nonce: self.nonce,
597                pos_reference: self.pos_reference,
598                base_price: self.base_price.clone(),
599            },
600            hash: None,
601            pow_hash: None,
602            approximated_rlp_size: 0,
603        };
604
605        block_header.approximated_rlp_size =
606            mem::size_of::<BlockHeaderRlpPart>()
607                + block_header
608                    .referee_hashes
609                    .size_of(&mut new_malloc_size_ops());
610
611        block_header
612    }
613
614    pub fn compute_block_logs_bloom_hash(
615        receipts: &Vec<Arc<BlockReceipts>>,
616    ) -> H256 {
617        let bloom = receipts.iter().map(|x| &x.receipts).flatten().fold(
618            Bloom::zero(),
619            |mut b, r| {
620                b.accrue_bloom(&r.log_bloom);
621                b
622            },
623        );
624
625        keccak(bloom)
626    }
627
628    pub fn compute_aggregated_bloom(blooms: Vec<Bloom>) -> Bloom {
629        blooms.into_iter().fold(Bloom::zero(), |mut res, bloom| {
630            res.accrue_bloom(&bloom);
631            res
632        })
633    }
634
635    pub fn compute_blame_state_root_vec_root(roots: Vec<H256>) -> H256 {
636        let mut accumulated_root = roots.last().unwrap().clone();
637        for i in (0..(roots.len() - 1)).rev() {
638            accumulated_root =
639                BlockHeaderBuilder::compute_blame_state_root_incremental(
640                    roots[i],
641                    accumulated_root,
642                );
643        }
644        accumulated_root
645    }
646
647    pub fn compute_blame_state_root_incremental(
648        first_root: H256, remaining_root: H256,
649    ) -> H256 {
650        let mut buffer = Vec::with_capacity(H256::len_bytes() * 2);
651        buffer.extend_from_slice(first_root.as_bytes());
652        buffer.extend_from_slice(remaining_root.as_bytes());
653        keccak(&buffer)
654    }
655}
656
657impl Encodable for BlockHeader {
658    fn rlp_append(&self, stream: &mut RlpStream) { self.stream_rlp(stream); }
659}
660
661impl Decodable for BlockHeader {
662    fn decode(r: &Rlp) -> Result<Self, DecoderError> {
663        let rlp_size = r.as_raw().len();
664        let mut rlp_part = BlockHeaderRlpPart {
665            parent_hash: r.val_at(0)?,
666            height: r.val_at(1)?,
667            timestamp: r.val_at(2)?,
668            author: r.val_at(3)?,
669            transactions_root: r.val_at(4)?,
670            deferred_state_root: r.val_at(5)?,
671            deferred_receipts_root: r.val_at(6)?,
672            deferred_logs_bloom_hash: r.val_at(7)?,
673            blame: r.val_at(8)?,
674            difficulty: r.val_at(9)?,
675            adaptive: r.val_at::<u8>(10)? == 1,
676            gas_limit: r.val_at(11)?,
677            referee_hashes: r.list_at(12)?,
678            custom: vec![],
679            nonce: r.val_at(13)?,
680            pos_reference: r.val_at(14).unwrap_or(None),
681            base_price: r.val_at(15).unwrap_or(None),
682        };
683        for i in (14
684            + rlp_part.pos_reference.is_some() as usize
685            + rlp_part.base_price.is_some() as usize)
686            ..r.item_count()?
687        {
688            if rlp_part.height
689                >= *CIP112_TRANSITION_HEIGHT.get().expect("initialized")
690            {
691                rlp_part.custom.push(r.val_at(i)?);
692            } else {
693                rlp_part.custom.push(r.at(i)?.as_raw().to_vec());
694            }
695        }
696
697        let mut header = BlockHeader {
698            rlp_part,
699            hash: None,
700            pow_hash: None,
701            approximated_rlp_size: rlp_size,
702        };
703        header.compute_hash();
704
705        Ok(header)
706    }
707}
708
709#[derive(Clone, Copy, Debug, Eq, RlpDecodable, RlpEncodable, PartialEq)]
710pub struct BasePrice {
711    pub core_base_price: U256,
712    pub espace_base_price: U256,
713}
714#[cfg(test)]
715mod tests {
716    use super::BlockHeaderBuilder;
717    use crate::{
718        hash::keccak,
719        receipt::{BlockReceipts, Receipt},
720        TransactionStatus,
721    };
722    use cfx_types::{Bloom, KECCAK_EMPTY_BLOOM, U256};
723    use std::{str::FromStr, sync::Arc};
724
725    #[test]
726    fn test_logs_bloom_hash_no_receipts() {
727        let receipts = vec![]; // Vec<_>
728        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
729        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
730
731        let receipts = (1..11)
732            .map(|_| {
733                Arc::new(BlockReceipts {
734                    receipts: vec![],
735                    block_number: 0,
736                    secondary_reward: U256::zero(),
737                    tx_execution_error_messages: vec![],
738                })
739            })
740            .collect(); // Vec<Arc<Vec<_>>>
741        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
742        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
743    }
744
745    #[test]
746    fn test_logs_bloom_hash_empty_receipts() {
747        let receipt = Receipt {
748            accumulated_gas_used: U256::zero(),
749            gas_fee: U256::zero(),
750            gas_sponsor_paid: false,
751            logs: vec![],
752            outcome_status: TransactionStatus::Success,
753            log_bloom: Bloom::zero(),
754            storage_sponsor_paid: false,
755            storage_collateralized: vec![],
756            storage_released: vec![],
757            burnt_gas_fee: None,
758        };
759
760        // 10 blocks with 10 empty receipts each
761        let receipts = (1..11)
762            .map(|_| {
763                Arc::new(BlockReceipts {
764                    receipts: (1..11).map(|_| receipt.clone()).collect(),
765                    block_number: 0,
766                    secondary_reward: U256::zero(),
767                    tx_execution_error_messages: vec!["".into(); 10],
768                })
769            })
770            .collect();
771        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
772        assert_eq!(hash, KECCAK_EMPTY_BLOOM);
773    }
774
775    #[test]
776    fn test_logs_bloom_hash() {
777        let block1 = BlockReceipts {
778            receipts: vec![
779                Receipt {
780                    accumulated_gas_used: 0.into(),
781                    gas_fee: 0.into(),
782                    gas_sponsor_paid: false,
783                    logs: vec![],
784                    outcome_status: TransactionStatus::Success,
785                    log_bloom: Bloom::from_str(
786                        "11111111111111111111111111111111\
787                         00000000000000000000000000000000\
788                         00000000000000000000000000000000\
789                         00000000000000000000000000000000\
790                         00000000000000000000000000000000\
791                         00000000000000000000000000000000\
792                         00000000000000000000000000000000\
793                         00000000000000000000000000000000\
794                         00000000000000000000000000000000\
795                         00000000000000000000000000000000\
796                         00000000000000000000000000000000\
797                         00000000000000000000000000000000\
798                         00000000000000000000000000000000\
799                         00000000000000000000000000000000\
800                         00000000000000000000000000000000\
801                         00000000000000000000000000000000",
802                    )
803                    .unwrap(),
804                    storage_sponsor_paid: false,
805                    storage_collateralized: vec![],
806                    storage_released: vec![],
807                    burnt_gas_fee: None,
808                },
809                Receipt {
810                    accumulated_gas_used: U256::zero(),
811                    gas_fee: U256::zero(),
812                    gas_sponsor_paid: false,
813                    logs: vec![],
814                    outcome_status: TransactionStatus::Success,
815                    log_bloom: Bloom::from_str(
816                        "00000000000000000000000000000000\
817                         22222222222222222222222222222222\
818                         00000000000000000000000000000000\
819                         00000000000000000000000000000000\
820                         00000000000000000000000000000000\
821                         00000000000000000000000000000000\
822                         00000000000000000000000000000000\
823                         00000000000000000000000000000000\
824                         00000000000000000000000000000000\
825                         00000000000000000000000000000000\
826                         00000000000000000000000000000000\
827                         00000000000000000000000000000000\
828                         00000000000000000000000000000000\
829                         00000000000000000000000000000000\
830                         00000000000000000000000000000000\
831                         00000000000000000000000000000000",
832                    )
833                    .unwrap(),
834                    storage_sponsor_paid: false,
835                    storage_collateralized: vec![],
836                    storage_released: vec![],
837                    burnt_gas_fee: None,
838                },
839            ],
840            block_number: 0,
841            secondary_reward: U256::zero(),
842            tx_execution_error_messages: vec!["".into(); 2],
843        };
844
845        let block2 = BlockReceipts {
846            receipts: vec![Receipt {
847                accumulated_gas_used: U256::zero(),
848                gas_fee: U256::zero(),
849                gas_sponsor_paid: false,
850                logs: vec![],
851                outcome_status: TransactionStatus::Success,
852                log_bloom: Bloom::from_str(
853                    "44444444444444440000000000000000\
854                     44444444444444440000000000000000\
855                     44444444444444440000000000000000\
856                     44444444444444440000000000000000\
857                     00000000000000000000000000000000\
858                     00000000000000000000000000000000\
859                     00000000000000000000000000000000\
860                     00000000000000000000000000000000\
861                     00000000000000000000000000000000\
862                     00000000000000000000000000000000\
863                     00000000000000000000000000000000\
864                     00000000000000000000000000000000\
865                     00000000000000000000000000000000\
866                     00000000000000000000000000000000\
867                     00000000000000000000000000000000\
868                     00000000000000000000000000000000",
869                )
870                .unwrap(),
871                storage_sponsor_paid: false,
872                storage_collateralized: vec![],
873                storage_released: vec![],
874                burnt_gas_fee: None,
875            }],
876            block_number: 0,
877            secondary_reward: U256::zero(),
878            tx_execution_error_messages: vec!["".into()],
879        };
880
881        let expected = keccak(
882            "55555555555555551111111111111111\
883             66666666666666662222222222222222\
884             44444444444444440000000000000000\
885             44444444444444440000000000000000\
886             00000000000000000000000000000000\
887             00000000000000000000000000000000\
888             00000000000000000000000000000000\
889             00000000000000000000000000000000\
890             00000000000000000000000000000000\
891             00000000000000000000000000000000\
892             00000000000000000000000000000000\
893             00000000000000000000000000000000\
894             00000000000000000000000000000000\
895             00000000000000000000000000000000\
896             00000000000000000000000000000000\
897             00000000000000000000000000000000"
898                .parse::<Bloom>()
899                .unwrap(),
900        );
901
902        let receipts = vec![Arc::new(block1), Arc::new(block2)];
903        let hash = BlockHeaderBuilder::compute_block_logs_bloom_hash(&receipts);
904        assert_eq!(hash, expected);
905    }
906}