miden_node_proto/domain/
proof_request.rs1use std::collections::BTreeMap;
2
3use miden_protobuf::{BuildUnchecked, ConversionResultExt, DecodeMessageExt, Verify};
4use miden_protocol::account::AccountId;
5use miden_protocol::batch::OrderedBatches;
6use miden_protocol::block::account_tree::AccountWitness;
7use miden_protocol::block::nullifier_tree::NullifierWitness;
8use miden_protocol::block::{BlockHeader, BlockInputs, ProposedBlock};
9use miden_protocol::note::{NoteId, NoteInclusionProof, Nullifier};
10use miden_protocol::transaction::PartialBlockchain;
11
12use crate::errors::ConversionError;
13use crate::generated as proto;
14
15#[derive(Debug)]
17pub struct BlockProofRequest {
18 pub tx_batches: OrderedBatches,
19 pub block_header: BlockHeader,
20 pub block_inputs: BlockInputs,
21}
22
23impl From<&BlockProofRequest> for proto::block_proving::BlockProofRequest {
24 fn from(value: &BlockProofRequest) -> Self {
25 Self {
26 batches: value.tx_batches.as_slice().iter().map(Into::into).collect(),
27 block_inputs: Some((&value.block_inputs).into()),
28 timestamp: value.block_header.timestamp(),
29 next_validator_config: Some(value.block_header.validator_config().into()),
30 next_protocol_config: value.block_header.next_protocol_config().map(Into::into),
31 }
32 }
33}
34
35impl From<BlockProofRequest> for proto::block_proving::BlockProofRequest {
36 fn from(value: BlockProofRequest) -> Self {
37 Self::from(&value)
38 }
39}
40
41impl BuildUnchecked for proto::block_proving::DecodedBlockProofRequest {
42 type Output = BlockProofRequest;
43 type Error = ConversionError;
44
45 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
49 let block_inputs = self.block_inputs.build_unchecked().context("block_inputs")?;
52 let batches = self.batches.build_unchecked()?;
55 let next_validator_config =
56 self.next_validator_config.verify().context("next_validator_config")?;
57 let next_protocol_config = self.next_protocol_config.verify()?;
58
59 let proposed_block =
60 ProposedBlock::new_at(block_inputs.clone(), batches.clone(), self.timestamp)
61 .map_err(ConversionError::new)?
62 .with_next_validator_config(next_validator_config)
63 .with_next_protocol_config(next_protocol_config);
64 let (block_header, _) =
65 proposed_block.into_header_and_body().map_err(ConversionError::new)?;
66
67 Ok(BlockProofRequest {
68 tx_batches: OrderedBatches::new(batches),
69 block_header,
70 block_inputs,
71 })
72 }
73}
74
75impl From<&BlockInputs> for proto::block_proving::BlockInputs {
76 fn from(value: &BlockInputs) -> Self {
77 Self {
78 prev_block_header: Some(value.prev_block_header().into()),
79 partial_blockchain: Some(value.partial_blockchain().into()),
80 account_witnesses: value
81 .account_witnesses()
82 .iter()
83 .map(|(account_id, witness)| proto::block_proving::AccountWitnessRecord {
84 account_id: Some((*account_id).into()),
85 witness: Some(witness.into()),
86 })
87 .collect(),
88 nullifier_witnesses: value
89 .nullifier_witnesses()
90 .iter()
91 .map(|(nullifier, witness)| proto::block_proving::NullifierWitness {
92 nullifier: Some(nullifier.as_word().into()),
93 opening: Some(witness.proof().clone().into()),
94 })
95 .collect(),
96 unauthenticated_note_proofs: value
97 .unauthenticated_note_proofs()
98 .iter()
99 .map(Into::into)
100 .collect(),
101 }
102 }
103}
104
105impl BuildUnchecked for proto::block_proving::DecodedBlockInputs {
106 type Output = BlockInputs;
107 type Error = ConversionError;
108
109 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
113 let prev_block_header: BlockHeader =
115 self.prev_block_header.build_unchecked().context("prev_block_header")?;
116 let partial_blockchain: PartialBlockchain =
118 self.partial_blockchain.build_unchecked().context("partial_blockchain")?;
119
120 let mut account_witnesses = BTreeMap::<AccountId, AccountWitness>::new();
121 for (index, record) in self.account_witnesses.into_inner().into_iter().enumerate() {
122 let account_id = record
123 .account_id
124 .verify()
125 .with_context(|| format!("account_witnesses[{index}].account_id"))?;
126 let witness = record
127 .witness
128 .verify()
129 .with_context(|| format!("account_witnesses[{index}].witness"))?;
130 if account_witnesses.insert(account_id, witness).is_some() {
131 return Err(ConversionError::message(format!(
132 "account_witnesses[{index}]: duplicate requested account ID {account_id}"
133 )));
134 }
135 }
136
137 let mut nullifier_witnesses = BTreeMap::<Nullifier, NullifierWitness>::new();
138 for (index, record) in self.nullifier_witnesses.into_inner().into_iter().enumerate() {
139 let nullifier = Nullifier::from_raw(record.nullifier);
140 let proof = record
141 .opening
142 .verify()
143 .with_context(|| format!("nullifier_witnesses[{index}].opening"))?;
144 if nullifier_witnesses.insert(nullifier, NullifierWitness::new(proof)).is_some() {
145 return Err(ConversionError::message(format!(
146 "nullifier_witnesses[{index}]: duplicate nullifier {nullifier}"
147 )));
148 }
149 }
150
151 let mut unauthenticated_note_proofs = BTreeMap::<NoteId, NoteInclusionProof>::new();
152 for (index, proof) in self.unauthenticated_note_proofs.into_inner().into_iter().enumerate()
153 {
154 let (note_id, proof) = proof
155 .verify()
156 .with_context(|| format!("unauthenticated_note_proofs[{index}]"))?;
157 if unauthenticated_note_proofs.insert(note_id, proof).is_some() {
158 return Err(ConversionError::message(format!(
159 "unauthenticated_note_proofs[{index}]: duplicate note ID {note_id}"
160 )));
161 }
162 }
163
164 Ok(BlockInputs::new(
165 prev_block_header,
166 partial_blockchain,
167 account_witnesses,
168 nullifier_witnesses,
169 unauthenticated_note_proofs,
170 ))
171 }
172}
173
174impl miden_node_persistence::ProtobufValue for BlockProofRequest {
175 type Message = proto::block_proving::BlockProofRequest;
176
177 fn to_proto(&self) -> Self::Message {
178 self.into()
179 }
180
181 fn from_proto(
182 message: Self::Message,
183 ) -> Result<Self, miden_node_persistence::PersistenceError> {
184 Ok(message.decode_and_build_unchecked()?)
185 }
186}