1use std::collections::HashSet;
2
3use crate::{
4 core::{self},
5 packed,
6 prelude::*,
7 utilities::{compact_to_difficulty, merkle_root},
8 U256,
9};
10
11impl Difficulty for packed::RawHeader {
12 fn difficulty(&self) -> U256 {
14 compact_to_difficulty(self.compact_target().unpack())
15 }
16}
17
18impl Difficulty for packed::Header {
19 fn difficulty(&self) -> U256 {
21 self.raw().difficulty()
22 }
23}
24
25impl ResetBlock for packed::Block {
26 fn reset_header(self) -> packed::Block {
28 let tx_hashes = self.as_reader().calc_tx_hashes();
29 let tx_witness_hashes = self.as_reader().calc_tx_witness_hashes();
30 self.reset_header_with_hashes(&tx_hashes[..], &tx_witness_hashes[..])
31 }
32
33 fn reset_header_with_hashes(
34 self,
35 tx_hashes: &[packed::Byte32],
36 tx_witness_hashes: &[packed::Byte32],
37 ) -> packed::Block {
38 let raw_transactions_root = merkle_root(tx_hashes);
39 let witnesses_root = merkle_root(tx_witness_hashes);
40 let transactions_root = merkle_root(&[raw_transactions_root, witnesses_root]);
41 let proposals_hash = self.as_reader().calc_proposals_hash();
42 let extra_hash = self.as_reader().calc_extra_hash().extra_hash();
43 let raw_header = self
44 .header()
45 .raw()
46 .as_builder()
47 .transactions_root(transactions_root)
48 .proposals_hash(proposals_hash)
49 .extra_hash(extra_hash)
50 .build();
51 let header = self.header().as_builder().raw(raw_header).build();
52 if let Some(extension) = self.extension() {
53 packed::BlockV1::new_builder()
54 .header(header)
55 .uncles(self.uncles())
56 .transactions(self.transactions())
57 .proposals(self.proposals())
58 .extension(extension)
59 .build()
60 .as_v0()
61 } else {
62 self.as_builder().header(header).build()
63 }
64 }
65}
66
67impl BuildCompactBlock for packed::CompactBlock {
68 fn build_from_block(
70 block: &core::BlockView,
71 prefilled_transactions_indexes: &HashSet<usize>,
72 ) -> packed::CompactBlock {
73 let prefilled_transactions_len = prefilled_transactions_indexes.len() + 1;
75 let mut short_ids: Vec<packed::ProposalShortId> = Vec::with_capacity(
76 block
77 .data()
78 .transactions()
79 .len()
80 .saturating_sub(prefilled_transactions_len),
81 );
82 let mut prefilled_transactions = Vec::with_capacity(prefilled_transactions_len);
83
84 for (transaction_index, transaction) in block.transactions().into_iter().enumerate() {
85 if prefilled_transactions_indexes.contains(&transaction_index)
86 || transaction.is_cellbase()
87 {
88 let prefilled_tx = packed::IndexTransaction::new_builder()
89 .index((transaction_index as u32).pack())
90 .transaction(transaction.data())
91 .build();
92 prefilled_transactions.push(prefilled_tx);
93 } else {
94 short_ids.push(transaction.proposal_short_id());
95 }
96 }
97
98 if let Some(extension) = block.data().extension() {
99 packed::CompactBlockV1::new_builder()
100 .header(block.data().header())
101 .short_ids(short_ids.pack())
102 .prefilled_transactions(prefilled_transactions.pack())
103 .uncles(block.uncle_hashes.clone())
104 .proposals(block.data().proposals())
105 .extension(extension)
106 .build()
107 .as_v0()
108 } else {
109 packed::CompactBlock::new_builder()
110 .header(block.data().header())
111 .short_ids(short_ids.pack())
112 .prefilled_transactions(prefilled_transactions.pack())
113 .uncles(block.uncle_hashes.clone())
114 .proposals(block.data().proposals())
115 .build()
116 }
117 }
118
119 fn block_short_ids(&self) -> Vec<Option<packed::ProposalShortId>> {
121 let txs_len = self.txs_len();
122 let mut block_short_ids: Vec<Option<packed::ProposalShortId>> = Vec::with_capacity(txs_len);
123 let prefilled_indexes = self
124 .prefilled_transactions()
125 .into_iter()
126 .map(|tx_index| tx_index.index().unpack())
127 .collect::<HashSet<usize>>();
128
129 let mut index = 0;
130 for i in 0..txs_len {
131 if prefilled_indexes.contains(&i) {
132 block_short_ids.push(None);
133 } else {
134 block_short_ids.push(self.short_ids().get(index));
135 index += 1;
136 }
137 }
138 block_short_ids
139 }
140
141 fn short_id_indexes(&self) -> Vec<usize> {
143 let prefilled_indexes_iter = self
144 .prefilled_transactions()
145 .into_iter()
146 .map(|i| i.index().unpack());
147
148 let prefilled_indexes: HashSet<usize> = prefilled_indexes_iter.collect();
149
150 (0..self.txs_len())
151 .filter(|index| !prefilled_indexes.contains(index))
152 .collect()
153 }
154}
155
156impl<'r> CalcExtraHash for packed::BlockReader<'r> {
157 fn calc_extra_hash(&self) -> core::ExtraHashView {
164 crate::core::ExtraHashView::new(self.calc_uncles_hash(), self.calc_extension_hash())
165 }
166}
167
168impl CalcExtraHash for packed::Block {
169 fn calc_extra_hash(&self) -> core::ExtraHashView {
172 self.as_reader().calc_extra_hash()
173 }
174}
175
176#[cfg(test)]
177mod test {
178 use crate::{h256, packed, prelude::*};
179 #[test]
180 fn empty_extra_hash() {
181 let block = packed::Block::new_builder().build();
182 let expect = h256!("0x0");
183 assert_eq!(block.calc_extra_hash().extra_hash(), expect.pack());
184 }
185}