1use std_shims::{
2 vec,
3 vec::Vec,
4 io::{self, Read, Write},
5};
6
7use crate::{
8 io::*,
9 primitives::{UpperBound, keccak256},
10 merkle::merkle_root,
11 transaction::{Input, Transaction},
12};
13
14pub(crate) const CORRECT_BLOCK_HASH_202612: [u8; 32] =
15 hex_literal::hex!("426d16cff04c71f8b16340b722dc4010a2dd3831c22041431f772547ba6e331a");
16pub(crate) const EXISTING_BLOCK_HASH_202612: [u8; 32] =
17 hex_literal::hex!("bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
18
19#[derive(Clone, PartialEq, Eq, Debug)]
21pub struct BlockHeader {
22 pub hardfork_version: u8,
26 pub hardfork_signal: u8,
30 pub timestamp: u64,
32 pub previous: [u8; 32],
34 pub nonce: u32,
39}
40
41impl BlockHeader {
42 pub const SIZE_UPPER_BOUND: UpperBound<usize> = UpperBound(
44 <u8 as VarInt>::UPPER_BOUND +
45 <u8 as VarInt>::UPPER_BOUND +
46 <u64 as VarInt>::UPPER_BOUND +
47 32 +
48 4,
49 );
50
51 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
53 VarInt::write(&self.hardfork_version, w)?;
54 VarInt::write(&self.hardfork_signal, w)?;
55 VarInt::write(&self.timestamp, w)?;
56 w.write_all(&self.previous)?;
57 w.write_all(&self.nonce.to_le_bytes())
58 }
59
60 pub fn serialize(&self) -> Vec<u8> {
62 let mut serialized = vec![];
63 self.write(&mut serialized).expect("write failed but <Vec as io::Write> doesn't fail");
64 serialized
65 }
66
67 pub fn read<R: Read>(r: &mut R) -> io::Result<BlockHeader> {
69 Ok(BlockHeader {
70 hardfork_version: VarInt::read(r)?,
71 hardfork_signal: VarInt::read(r)?,
72 timestamp: VarInt::read(r)?,
73 previous: read_bytes(r)?,
74 nonce: read_bytes(r).map(u32::from_le_bytes)?,
75 })
76 }
77}
78
79#[derive(Clone, PartialEq, Eq, Debug)]
81#[expect(clippy::partial_pub_fields)]
82pub struct Block {
83 pub header: BlockHeader,
85 miner_transaction: Transaction,
89 pub transactions: Vec<[u8; 32]>,
91}
92
93impl Block {
94 pub const MAX_TRANSACTIONS: usize = 0x1000_0000;
112
113 pub fn new(
119 header: BlockHeader,
120 miner_transaction: Transaction,
121 transactions: Vec<[u8; 32]>,
122 ) -> Option<Block> {
123 {
127 let inputs = &miner_transaction.prefix().inputs;
128 if inputs.len() != 1 {
129 None?;
130 }
131 match inputs[0] {
132 Input::Gen(_number) => {}
133 Input::ToKey { .. } => None?,
134 }
135 }
136
137 Some(Block { header, miner_transaction, transactions })
138 }
139
140 pub fn number(&self) -> usize {
142 match &self.miner_transaction {
143 Transaction::V1 { prefix, .. } | Transaction::V2 { prefix, .. } => {
144 match prefix.inputs.first() {
145 Some(Input::Gen(number)) => *number,
146 _ => panic!("invalid miner transaction accepted into block"),
147 }
148 }
149 }
150 }
151
152 pub fn miner_transaction(&self) -> &Transaction {
154 &self.miner_transaction
155 }
156
157 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
159 self.header.write(w)?;
160 self.miner_transaction.write(w)?;
161 VarInt::write(&self.transactions.len(), w)?;
162 for tx in &self.transactions {
163 w.write_all(tx)?;
164 }
165 Ok(())
166 }
167
168 pub fn serialize(&self) -> Vec<u8> {
170 let mut serialized = vec![];
171 self.write(&mut serialized).expect("write failed but <Vec as io::Write> doesn't fail");
172 serialized
173 }
174
175 pub fn serialize_pow_hash(&self) -> Vec<u8> {
183 let mut blob = self.header.serialize();
184
185 let mut transactions = Vec::with_capacity(self.transactions.len() + 1);
186 transactions.push(self.miner_transaction.hash());
187 transactions.extend_from_slice(&self.transactions);
188
189 blob.extend_from_slice(
190 &merkle_root(transactions)
191 .expect("the tree will not be empty, the miner tx is always present"),
192 );
193 VarInt::write(&(1 + self.transactions.len()), &mut blob)
194 .expect("write failed but <Vec as io::Write> doesn't fail");
195 blob
196 }
197
198 pub fn hash(&self) -> [u8; 32] {
200 let mut hashable = self.serialize_pow_hash();
201 let mut hashing_blob = Vec::with_capacity(<usize as VarInt>::UPPER_BOUND + hashable.len());
204 VarInt::write(
205 &u64::try_from(hashable.len()).expect("length of block hash's preimage exceeded u64::MAX"),
206 &mut hashing_blob,
207 )
208 .expect("write failed but <Vec as io::Write> doesn't fail");
209 hashing_blob.append(&mut hashable);
210
211 let hash = keccak256(hashing_blob);
212 if hash == CORRECT_BLOCK_HASH_202612 {
215 return EXISTING_BLOCK_HASH_202612;
216 }
217 hash
218 }
219
220 pub fn read<R: Read>(r: &mut R) -> io::Result<Block> {
226 let header = BlockHeader::read(r)?;
227
228 let miner_transaction = Transaction::read(r)?;
229
230 let transactions: usize = VarInt::read(r)?;
231 if transactions >= Self::MAX_TRANSACTIONS {
232 Err(io::Error::other("amount of transaction exceeds limit"))?;
233 }
234 let transactions = (0 .. transactions).map(|_| read_bytes(r)).collect::<Result<_, _>>()?;
235
236 Block::new(header, miner_transaction, transactions)
237 .ok_or_else(|| io::Error::other("block failed sanity checks"))
238 }
239}