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().to_vec()
245 }
246
247 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 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 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 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 .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 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![]; 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 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}