1mod 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;
30pub 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: H256,
40 height: BlockHeight,
42 timestamp: u64,
44 author: Address,
46 transactions_root: H256,
48 deferred_state_root: H256,
50 deferred_receipts_root: H256,
52 deferred_logs_bloom_hash: H256,
54 blame: u32,
59 difficulty: U256,
61 adaptive: bool,
63 gas_limit: U256,
65 referee_hashes: Vec<H256>,
67 custom: Vec<Bytes>,
69 nonce: U256,
71 pos_reference: Option<H256>,
73 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#[derive(Clone, Debug, Eq)]
100pub struct BlockHeader {
101 rlp_part: BlockHeaderRlpPart,
102 hash: Option<H256>,
104 pub pow_hash: Option<H256>,
106 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 pub fn approximated_rlp_size(&self) -> usize { self.approximated_rlp_size }
133
134 pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
136
137 pub fn height(&self) -> u64 { self.height }
139
140 pub fn timestamp(&self) -> u64 { self.timestamp }
142
143 pub fn author(&self) -> &Address { &self.author }
145
146 pub fn transactions_root(&self) -> &H256 { &self.transactions_root }
148
149 pub fn deferred_state_root(&self) -> &H256 { &self.deferred_state_root }
151
152 pub fn deferred_receipts_root(&self) -> &H256 {
154 &self.deferred_receipts_root
155 }
156
157 pub fn deferred_logs_bloom_hash(&self) -> &H256 {
159 &self.deferred_logs_bloom_hash
160 }
161
162 pub fn blame(&self) -> u32 { self.blame }
164
165 pub fn difficulty(&self) -> &U256 { &self.difficulty }
167
168 pub fn adaptive(&self) -> bool { self.adaptive }
170
171 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 pub fn referee_hashes(&self) -> &Vec<H256> { &self.referee_hashes }
187
188 pub fn custom(&self) -> &Vec<Bytes> { &self.custom }
190
191 pub fn nonce(&self) -> U256 { self.nonce }
193
194 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 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 pub fn set_nonce(&mut self, nonce: U256) { self.nonce = nonce; }
216
217 pub fn set_timestamp(&mut self, timestamp: u64) {
219 self.timestamp = timestamp;
220 }
221
222 pub fn set_custom(&mut self, custom: Vec<Bytes>) { self.custom = custom; }
224
225 pub fn compute_hash(&mut self) -> H256 {
227 let hash = self.hash();
228 self.hash = Some(hash);
229 hash
230 }
231
232 pub fn hash(&self) -> H256 {
234 self.hash.unwrap_or_else(|| keccak(self.rlp()))
235 }
236
237 pub fn problem_hash(&self) -> H256 { keccak(self.rlp_without_nonce()) }
239
240 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 pub fn rlp(&self) -> Bytes {
249 let mut stream = RlpStream::new();
250 self.stream_rlp(&mut stream);
251 stream.out()
252 }
253
254 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 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 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 .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 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![]; 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(); 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 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}