1use core::ops::Deref;
5
6use bee_pow::providers::{miner::Miner, NonceProvider, NonceProviderBuilder};
7use crypto::hashes::{blake2b::Blake2b256, Digest};
8use packable::{
9 error::{UnexpectedEOF, UnpackError, UnpackErrorExt},
10 packer::Packer,
11 unpacker::{CounterUnpacker, SliceUnpacker, Unpacker},
12 Packable, PackableExt,
13};
14
15use crate::{
16 parent::Parents,
17 payload::{OptionalPayload, Payload},
18 protocol::ProtocolParameters,
19 BlockId, Error, PROTOCOL_VERSION,
20};
21
22#[derive(Clone)]
24#[must_use]
25pub struct BlockBuilder<P: NonceProvider = Miner> {
26 protocol_version: Option<u8>,
27 parents: Parents,
28 payload: Option<Payload>,
29 nonce_provider: Option<P>,
30}
31
32impl<P: NonceProvider> BlockBuilder<P> {
33 const DEFAULT_NONCE: u64 = 0;
34
35 #[inline(always)]
37 pub fn new(parents: Parents) -> Self {
38 Self {
39 protocol_version: None,
40 parents,
41 payload: None,
42 nonce_provider: None,
43 }
44 }
45
46 #[inline(always)]
48 pub fn with_protocol_version(mut self, protocol_version: u8) -> Self {
49 self.protocol_version = Some(protocol_version);
50 self
51 }
52
53 #[inline(always)]
55 pub fn with_payload(mut self, payload: Payload) -> Self {
56 self.payload = Some(payload);
57 self
58 }
59
60 #[inline(always)]
62 pub fn with_nonce_provider(mut self, nonce_provider: P) -> Self {
63 self.nonce_provider = Some(nonce_provider);
64 self
65 }
66
67 pub fn finish(self, min_pow_score: u32) -> Result<Block, Error> {
69 verify_payload(self.payload.as_ref())?;
70
71 let mut block = Block {
72 protocol_version: self.protocol_version.unwrap_or(PROTOCOL_VERSION),
73 parents: self.parents,
74 payload: self.payload.into(),
75 nonce: 0,
76 };
77
78 let block_bytes = block.pack_to_vec();
79
80 if block_bytes.len() > Block::LENGTH_MAX {
81 return Err(Error::InvalidBlockLength(block_bytes.len()));
82 }
83
84 let nonce_provider = self.nonce_provider.unwrap_or_else(|| P::Builder::new().finish());
85
86 block.nonce = nonce_provider
87 .nonce(
88 &block_bytes[..block_bytes.len() - core::mem::size_of::<u64>()],
89 min_pow_score,
90 )
91 .unwrap_or(Self::DEFAULT_NONCE);
92
93 Ok(block)
94 }
95}
96
97#[derive(Clone, Debug, Eq, PartialEq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100pub struct Block {
101 protocol_version: u8,
103 parents: Parents,
105 payload: OptionalPayload,
107 nonce: u64,
109}
110
111impl Block {
112 pub const LENGTH_MIN: usize = 46;
114 pub const LENGTH_MAX: usize = 32768;
116
117 #[inline(always)]
119 pub fn build(parents: Parents) -> BlockBuilder {
120 BlockBuilder::new(parents)
121 }
122
123 #[inline(always)]
125 pub fn protocol_version(&self) -> u8 {
126 self.protocol_version
127 }
128
129 #[inline(always)]
131 pub fn parents(&self) -> &Parents {
132 &self.parents
133 }
134
135 #[inline(always)]
137 pub fn payload(&self) -> Option<&Payload> {
138 self.payload.as_ref()
139 }
140
141 #[inline(always)]
143 pub fn nonce(&self) -> u64 {
144 self.nonce
145 }
146
147 #[inline(always)]
149 pub fn id(&self) -> BlockId {
150 BlockId::new(Blake2b256::digest(&self.pack_to_vec()).into())
151 }
152
153 #[inline(always)]
155 pub fn into_parents(self) -> Parents {
156 self.parents
157 }
158
159 pub fn unpack_strict<T: AsRef<[u8]>>(
162 bytes: T,
163 visitor: &<Self as Packable>::UnpackVisitor,
164 ) -> Result<Self, UnpackError<<Self as Packable>::UnpackError, UnexpectedEOF>> {
165 let mut unpacker = CounterUnpacker::new(SliceUnpacker::new(bytes.as_ref()));
166 let block = Self::unpack::<_, true>(&mut unpacker, visitor)?;
167
168 if u8::unpack::<_, true>(&mut unpacker, &()).is_ok() {
170 return Err(UnpackError::Packable(Error::RemainingBytesAfterBlock));
171 }
172
173 Ok(block)
174 }
175}
176
177impl Packable for Block {
178 type UnpackError = Error;
179 type UnpackVisitor = ProtocolParameters;
180
181 fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
182 self.protocol_version.pack(packer)?;
183 self.parents.pack(packer)?;
184 self.payload.pack(packer)?;
185 self.nonce.pack(packer)?;
186
187 Ok(())
188 }
189
190 fn unpack<U: Unpacker, const VERIFY: bool>(
191 unpacker: &mut U,
192 visitor: &Self::UnpackVisitor,
193 ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
194 let start_opt = unpacker.read_bytes();
195
196 let protocol_version = u8::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
197
198 if VERIFY && protocol_version != visitor.protocol_version() {
199 return Err(UnpackError::Packable(Error::ProtocolVersionMismatch {
200 expected: visitor.protocol_version(),
201 actual: protocol_version,
202 }));
203 }
204
205 let parents = Parents::unpack::<_, VERIFY>(unpacker, &())?;
206 let payload = OptionalPayload::unpack::<_, VERIFY>(unpacker, visitor)?;
207
208 if VERIFY {
209 verify_payload(payload.deref().as_ref()).map_err(UnpackError::Packable)?;
210 }
211
212 let nonce = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
213
214 let block = Self {
215 protocol_version,
216 parents,
217 payload,
218 nonce,
219 };
220
221 if VERIFY {
222 let block_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) {
223 end - start
224 } else {
225 block.packed_len()
226 };
227
228 if block_len > Block::LENGTH_MAX {
229 return Err(UnpackError::Packable(Error::InvalidBlockLength(block_len)));
230 }
231 }
232
233 Ok(block)
234 }
235}
236
237fn verify_payload(payload: Option<&Payload>) -> Result<(), Error> {
238 if !matches!(
239 payload,
240 None | Some(Payload::Transaction(_)) | Some(Payload::Milestone(_)) | Some(Payload::TaggedData(_))
241 ) {
242 Err(Error::InvalidPayloadKind(payload.unwrap().kind()))
244 } else {
245 Ok(())
246 }
247}
248
249#[cfg(feature = "dto")]
250#[allow(missing_docs)]
251pub mod dto {
252 use serde::{Deserialize, Serialize};
253
254 use super::*;
255 use crate::{error::dto::DtoError, payload::dto::PayloadDto, protocol::ProtocolParameters};
256
257 #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
259 pub struct BlockDto {
260 #[serde(rename = "protocolVersion")]
262 pub protocol_version: u8,
263 pub parents: Vec<String>,
265 #[serde(skip_serializing_if = "Option::is_none")]
267 pub payload: Option<PayloadDto>,
268 pub nonce: String,
270 }
271
272 impl From<&Block> for BlockDto {
273 fn from(value: &Block) -> Self {
274 BlockDto {
275 protocol_version: value.protocol_version(),
276 parents: value.parents().iter().map(BlockId::to_string).collect(),
277 payload: value.payload().map(Into::into),
278 nonce: value.nonce().to_string(),
279 }
280 }
281 }
282
283 impl Block {
284 pub fn try_from_dto(value: &BlockDto, protocol_parameters: &ProtocolParameters) -> Result<Block, DtoError> {
285 let parents = Parents::new(
286 value
287 .parents
288 .iter()
289 .map(|m| m.parse::<BlockId>().map_err(|_| DtoError::InvalidField("parents")))
290 .collect::<Result<Vec<BlockId>, DtoError>>()?,
291 )?;
292
293 let mut builder = BlockBuilder::new(parents)
294 .with_protocol_version(value.protocol_version)
295 .with_nonce_provider(
296 value
297 .nonce
298 .parse::<u64>()
299 .map_err(|_| DtoError::InvalidField("nonce"))?,
300 );
301 if let Some(p) = value.payload.as_ref() {
302 builder = builder.with_payload(Payload::try_from_dto(p, protocol_parameters)?);
303 }
304
305 Ok(builder.finish(protocol_parameters.min_pow_score())?)
306 }
307 }
308}