miden_protocol/block/
signed_block.rs1use miden_core::Word;
2use miden_crypto::dsa::ecdsa_k256_keccak::Signature;
3
4use crate::block::{BlockBody, BlockHeader, BlockNumber};
5use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
6
7#[derive(Debug, thiserror::Error)]
11pub enum SignedBlockError {
12 #[error(
13 "ECDSA signature verification failed based on the signed block's header commitment, validator public key and signature"
14 )]
15 InvalidSignature,
16 #[error(
17 "header tx commitment ({header_tx_commitment}) does not match body tx commitment ({body_tx_commitment})"
18 )]
19 TxCommitmentMismatch {
20 header_tx_commitment: Word,
21 body_tx_commitment: Word,
22 },
23 #[error(
24 "signed block previous block commitment ({expected}) does not match expected parent's block commitment ({parent})"
25 )]
26 ParentCommitmentMismatch { expected: Word, parent: Word },
27 #[error("parent block number ({parent}) is not signed block number - 1 ({expected})")]
28 ParentNumberMismatch {
29 expected: BlockNumber,
30 parent: BlockNumber,
31 },
32 #[error(
33 "signed block header note root ({header_root}) does not match the corresponding body's note root ({body_root})"
34 )]
35 NoteRootMismatch { header_root: Word, body_root: Word },
36 #[error("supplied parent block ({parent}) cannot be parent to genesis block")]
37 GenesisBlockHasNoParent { parent: BlockNumber },
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct SignedBlock {
48 header: BlockHeader,
50
51 body: BlockBody,
53
54 signature: Signature,
56}
57
58impl SignedBlock {
59 pub fn new(
67 header: BlockHeader,
68 body: BlockBody,
69 signature: Signature,
70 ) -> Result<Self, SignedBlockError> {
71 let signed_block = Self { header, body, signature };
72
73 signed_block.validate_signature()?;
75
76 signed_block.validate_tx_commitment()?;
78
79 signed_block.validate_note_root()?;
81
82 Ok(signed_block)
83 }
84
85 pub fn new_unchecked(header: BlockHeader, body: BlockBody, signature: Signature) -> Self {
92 Self { header, signature, body }
93 }
94
95 pub fn header(&self) -> &BlockHeader {
97 &self.header
98 }
99
100 pub fn body(&self) -> &BlockBody {
102 &self.body
103 }
104
105 pub fn signature(&self) -> &Signature {
107 &self.signature
108 }
109
110 pub fn into_parts(self) -> (BlockHeader, BlockBody, Signature) {
112 (self.header, self.body, self.signature)
113 }
114
115 fn validate_signature(&self) -> Result<(), SignedBlockError> {
117 if !self.signature.verify(self.header.commitment(), self.header.validator_key()) {
118 Err(SignedBlockError::InvalidSignature)
119 } else {
120 Ok(())
121 }
122 }
123
124 fn validate_tx_commitment(&self) -> Result<(), SignedBlockError> {
129 let header_tx_commitment = self.header.tx_commitment();
130 let body_tx_commitment = self.body.transactions().commitment();
131 if header_tx_commitment != body_tx_commitment {
132 Err(SignedBlockError::TxCommitmentMismatch { header_tx_commitment, body_tx_commitment })
133 } else {
134 Ok(())
135 }
136 }
137
138 fn validate_note_root(&self) -> Result<(), SignedBlockError> {
142 let header_root = self.header.note_root();
143 let body_root = self.body.compute_block_note_tree().root();
144 if header_root != body_root {
145 Err(SignedBlockError::NoteRootMismatch { header_root, body_root })
146 } else {
147 Ok(())
148 }
149 }
150
151 pub fn validate_parent(&self, parent_block: &BlockHeader) -> Result<(), SignedBlockError> {
162 if let Some(expected) = self.header.block_num().checked_sub(1) {
164 let parent = parent_block.block_num();
165 if expected != parent {
166 return Err(SignedBlockError::ParentNumberMismatch { expected, parent });
167 }
168
169 let expected = self.header.prev_block_commitment();
171 let parent = parent_block.commitment();
172 if expected != parent {
173 return Err(SignedBlockError::ParentCommitmentMismatch { expected, parent });
174 }
175
176 Ok(())
177 } else {
178 let parent = parent_block.block_num();
180 Err(SignedBlockError::GenesisBlockHasNoParent { parent })
181 }
182 }
183}
184
185impl Serializable for SignedBlock {
189 fn write_into<W: ByteWriter>(&self, target: &mut W) {
190 self.header.write_into(target);
191 self.body.write_into(target);
192 self.signature.write_into(target);
193 }
194}
195
196impl Deserializable for SignedBlock {
197 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
198 let block = Self {
199 header: BlockHeader::read_from(source)?,
200 body: BlockBody::read_from(source)?,
201 signature: Signature::read_from(source)?,
202 };
203
204 Ok(block)
205 }
206}