• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Neptune-Crypto / neptune-core / 15261546953

26 May 2025 04:35PM UTC coverage: 71.839% (+0.1%) from 71.731%
15261546953

push

github

jan-ferdinand
ci: Fix coverage workflow

Due to a regression (?) in the rustc compiler, the code coverage
workflow has been failing since 2025-05-20. Temporarily use a version of
nightly that is known to work, until the underlying issue has been
resolved.

20196 of 28113 relevant lines covered (71.84%)

405411.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.1
/src/api/tx_initiation/builder/transaction_proof_builder.rs
1
//! This module implements a builder for transaction proofs.
2
//!
3
//! There are different levels of [TransactionProof] that
4
//! can be generated.  The desired proof can be specified with [TransactionProofType].
5
//!
6
//! With exception of `TransactionProofType::PrimitiveWitness`, proof generation
7
//! is a very CPU and RAM intensive process.  Each type of proof has different
8
//! hardware requirements.  Also the complexity is affected by the type and size
9
//! of transaction.
10
//!
11
//! Before a transaction can be confirmed in a block it must have a SingleProof
12
//! which is the hardest proof to generate.
13
//!
14
//! see [Transaction Initiation Sequence](super::super#transaction-initiation-sequence)
15
//!
16
//! If you have a powerful enough machine, you can generate a ProofCollection or
17
//! SingleProof yourself before passing the transaction to neptune-core.  This
18
//! takes load off the entire network and may lower the transaction fee
19
//! requirements.
20
//!
21
//! see [Client Provides Proof Initiation Sequence](super::super#client-provides-proof-initiation-sequence)
22
//!
23
//! see [builder](super) for examples of using the builders together.
24

25
use std::borrow::Borrow;
26
use std::borrow::Cow;
27
use std::sync::Arc;
28

29
use super::proof_builder::ProofBuilder;
30
use crate::api::tx_initiation::error::CreateProofError;
31
use crate::api::tx_initiation::error::ProofRequirement;
32
use crate::models::blockchain::transaction::primitive_witness::PrimitiveWitness;
33
use crate::models::blockchain::transaction::transaction_proof::TransactionProofType;
34
use crate::models::blockchain::transaction::validity::proof_collection::ProofCollection;
35
use crate::models::blockchain::transaction::validity::single_proof::SingleProof;
36
use crate::models::blockchain::transaction::validity::single_proof::SingleProofWitness;
37
use crate::models::blockchain::transaction::TransactionProof;
38
use crate::models::proof_abstractions::tasm::program::ConsensusProgram;
39
use crate::models::proof_abstractions::tasm::program::TritonVmProofJobOptions;
40
use crate::models::proof_abstractions::SecretWitness;
41
use crate::models::state::transaction_details::TransactionDetails;
42
use crate::triton_vm::proof::Claim;
43
use crate::triton_vm::vm::NonDeterminism;
44
use crate::triton_vm_job_queue::vm_job_queue;
45
use crate::triton_vm_job_queue::TritonVmJobQueue;
46

47
/// a builder for [TransactionProof]
48
///
49
/// see [module docs](self) for details.
50
#[derive(Debug, Default)]
51
pub struct TransactionProofBuilder<'a> {
52
    // these 3 types apply to any TransactionProofType
53
    transaction_details: Option<&'a TransactionDetails>,
54
    primitive_witness: Option<PrimitiveWitness>,
55
    primitive_witness_ref: Option<&'a PrimitiveWitness>,
56

57
    // these 3 types apply only to SingleProof
58
    proof_collection: Option<ProofCollection>,
59
    single_proof_witness: Option<&'a SingleProofWitness>,
60
    claim_and_nondeterminism: Option<(Claim, NonDeterminism)>,
61

62
    job_queue: Option<Arc<TritonVmJobQueue>>,
63
    proof_job_options: Option<TritonVmProofJobOptions>,
64
    valid_mock: Option<bool>,
65
}
66

67
impl<'a> TransactionProofBuilder<'a> {
68
    /// instantiate
69
    pub fn new() -> Self {
1,200✔
70
        Default::default()
1,200✔
71
    }
1,200✔
72

73
    /// add transaction details (optional)
74
    pub fn transaction_details(mut self, transaction_details: &'a TransactionDetails) -> Self {
1,104✔
75
        self.transaction_details = Some(transaction_details);
1,104✔
76
        self
1,104✔
77
    }
1,104✔
78

79
    /// add primitive witness (optional)
80
    ///
81
    /// Note that a `PrimitiveWitness` contains a `TransactionKernel` which is a
82
    /// field of `Transaction`.  Thus when generating a transaction it can avoid
83
    /// duplicate work to generate a witness, clone the kernel, provide the
84
    /// witness here, and then provide the kernel to the `TransactionBuilder`.
85
    ///
86
    /// It is also possible and may be more convenient to work only with
87
    /// `TransactionDetails`.
88
    pub fn primitive_witness(mut self, witness: PrimitiveWitness) -> Self {
1,104✔
89
        self.primitive_witness = Some(witness);
1,104✔
90
        self
1,104✔
91
    }
1,104✔
92

93
    /// add transaction details reference (optional)
94
    ///
95
    /// Note that if the target proof-type is `PrimitiveWitness` then the
96
    /// reference will be cloned when building and it may be better to use the
97
    /// `primitive_witness()` method.
98
    pub fn primitive_witness_ref(mut self, witness: &'a PrimitiveWitness) -> Self {
22✔
99
        self.primitive_witness_ref = Some(witness);
22✔
100
        self
22✔
101
    }
22✔
102

103
    /// add proof collection (optional)
104
    ///
105
    /// only used for building single-proof
106
    pub fn proof_collection(mut self, proof_collection: ProofCollection) -> Self {
×
107
        self.proof_collection = Some(proof_collection);
×
108
        self
×
109
    }
×
110

111
    /// add single proof witness (optional)
112
    ///
113
    /// only used for building single-proof
114
    pub fn single_proof_witness(mut self, single_proof_witness: &'a SingleProofWitness) -> Self {
70✔
115
        self.single_proof_witness = Some(single_proof_witness);
70✔
116
        self
70✔
117
    }
70✔
118

119
    /// add claim and non-determinism (optional)
120
    ///
121
    /// only used for building single-proof
122
    pub fn claim_and_nondeterminism(
×
123
        mut self,
×
124
        claim_and_nondeterminism: (Claim, NonDeterminism),
×
125
    ) -> Self {
×
126
        self.claim_and_nondeterminism = Some(claim_and_nondeterminism);
×
127
        self
×
128
    }
×
129

130
    /// add job queue (optional)
131
    ///
132
    /// if not provided then the process-wide [vm_job_queue()] will be used.
133
    pub fn job_queue(mut self, job_queue: Arc<TritonVmJobQueue>) -> Self {
1,200✔
134
        self.job_queue = Some(job_queue);
1,200✔
135
        self
1,200✔
136
    }
1,200✔
137

138
    /// add job options. (required)
139
    ///
140
    /// note: can be obtained via `TritonVmProofJobOptions::from(Args)`
141
    ///
142
    /// There is also `TritonVmProofJobOptionsBuilder`
143
    pub fn proof_job_options(mut self, proof_job_options: TritonVmProofJobOptions) -> Self {
1,200✔
144
        self.proof_job_options = Some(proof_job_options);
1,200✔
145
        self
1,200✔
146
    }
1,200✔
147

148
    /// create valid or invalid mock proof. (optional)
149
    ///
150
    /// valid mock proofs pass proof verification; invalid mock proofs do not.
151
    ///
152
    /// see [NeptuneProof](crate::models::blockchain::transaction::validity::neptune_proof::NeptuneProof)
153
    ///
154
    /// default = true
155
    ///
156
    /// only applies if the network uses mock proofs, eg regtest.
157
    ///
158
    /// does not apply to TransactionProof::PrimitiveWitness
159
    pub fn valid_mock(mut self, valid_mock: bool) -> Self {
×
160
        self.valid_mock = Some(valid_mock);
×
161
        self
×
162
    }
×
163

164
    /// generate the proof.
165
    ///
166
    /// ## Required (one-of)
167
    ///
168
    /// The following are individually optional, but at least one must be
169
    /// provided, else an error will result. (ProofRequirement::TransactionProofInput)
170
    ///
171
    /// * transaction_details()
172
    /// * primitive_witness()
173
    /// * primitive_witness_ref()
174
    /// * proof_collection()
175
    /// * single_proof_witness()
176
    /// * claim_and_nondeterminism()
177
    ///
178
    /// ## Evaluation
179
    ///
180
    /// if the network uses mock proofs (eg Network::RegTest), this will return
181
    /// immediately with a mock `TransactionProof`.
182
    ///
183
    /// if the target proof-type is Witness, this will return immediately.
184
    ///
185
    /// otherwise it will initiate an async job that could take many minutes.
186
    ///
187
    /// The provided inputs are evaluated in the following order, which
188
    /// generally is in order of most to least efficient. Evaluation ends at the
189
    /// first match in this list:
190
    ///
191
    /// if target proof_type is SingleProof:
192
    /// * claim_and_nondeterminism()
193
    /// * single_proof_witness()
194
    /// * proof_collection()
195
    ///
196
    /// for any proof-type:
197
    /// * primitive_witness()
198
    /// * primitive_witness_ref()
199
    /// * transaction_details()
200
    ///
201
    /// note that these jobs occur in a global (per process) job queue that only
202
    /// permits one VM job to process at a time.  This prevents parallel jobs
203
    /// from bringing the machine to its knees when each is using all available
204
    /// CPU cores and RAM.
205
    ///
206
    /// Given the serialized nature of the job-queue, it is possible or even likely
207
    /// that other jobs may precede this one.
208
    ///
209
    /// One can query the job_queue to determine how many jobs are in the queue.
210
    ///
211
    /// ## RegTest mode
212
    ///
213
    /// mock proofs are used on the regtest network (only) because they can be
214
    /// generated instantly.
215
    ///
216
    /// ## External Process
217
    ///
218
    /// Proofs are generated in the Triton VM. The proof generation occurs in a
219
    /// separate executable, `triton-vm-prover`, which is spawned by the
220
    /// job-queue for each proving job.  Only one `triton-vm-prover` process
221
    /// should be executing at a time for a given neptune-core instance.
222
    ///
223
    /// If the external process is killed for any reason, the proof-generation job will fail
224
    /// and this method will return an error.
225
    ///
226
    /// ## Cancellation
227
    ///
228
    /// See [TritonVmProofJobOptions::cancel_job_rx].
229
    ///
230
    /// note that cancelling the future returned by build() will NOT cancel the
231
    /// job in the job-queue, as that runs in a separately spawned tokio task
232
    /// managed by the job-queue.
233
    pub async fn build(self) -> Result<TransactionProof, CreateProofError> {
1,200✔
234
        let TransactionProofBuilder {
235
            transaction_details,
1,200✔
236
            primitive_witness,
1,200✔
237
            primitive_witness_ref,
1,200✔
238
            claim_and_nondeterminism,
1,200✔
239
            single_proof_witness,
1,200✔
240
            proof_collection,
1,200✔
241
            job_queue,
1,200✔
242
            proof_job_options,
1,200✔
243
            valid_mock,
1,200✔
244
        } = self;
1,200✔
245

246
        let proof_job_options = proof_job_options.ok_or(ProofRequirement::ProofJobOptions)?;
1,200✔
247

248
        let valid_mock = valid_mock.unwrap_or(true);
1,200✔
249
        let job_queue = job_queue.unwrap_or_else(vm_job_queue);
1,200✔
250

251
        // note: evaluation order must match order stated in the method doc-comment.
252

253
        if proof_job_options.job_settings.proof_type.is_single_proof() {
1,200✔
254
            // claim, nondeterminism --> single proof
255
            if let Some((c, nd)) = claim_and_nondeterminism {
154✔
256
                return gen_single(c, || nd, job_queue, proof_job_options, valid_mock).await;
×
257
            }
258
            // single-proof-witness --> single proof
259
            else if let Some(w) = single_proof_witness {
154✔
260
                let c = w.claim();
70✔
261
                return gen_single(
70✔
262
                    c,
70✔
263
                    || w.nondeterminism(),
70✔
264
                    job_queue,
70✔
265
                    proof_job_options,
70✔
266
                    valid_mock,
70✔
267
                )
268
                .await;
70✔
269
            }
270
            // proof-collection --> single proof
271
            else if let Some(pc) = proof_collection {
84✔
272
                let w = SingleProofWitness::from_collection(pc);
×
273
                let c = w.claim();
×
274
                return gen_single(
×
275
                    c,
×
276
                    || w.nondeterminism(),
×
277
                    job_queue,
×
278
                    proof_job_options,
×
279
                    valid_mock,
×
280
                )
281
                .await;
×
282
            }
84✔
283
        }
1,046✔
284

285
        // owned primitive witness --> proof_type
286
        if let Some(w) = primitive_witness {
1,130✔
287
            return from_witness(Cow::Owned(w), job_queue, proof_job_options, valid_mock).await;
1,104✔
288
        }
289
        // primitive witness reference --> proof_type
290
        else if let Some(w) = primitive_witness_ref {
26✔
291
            return from_witness(Cow::Borrowed(w), job_queue, proof_job_options, valid_mock).await;
26✔
292
        }
293
        // transaction_details --> proof_type
294
        else if let Some(d) = transaction_details {
×
295
            let w = d.primitive_witness();
×
296
            return from_witness(Cow::Owned(w), job_queue, proof_job_options, valid_mock).await;
×
297
        }
×
298

299
        Err(ProofRequirement::TransactionProofInput.into())
×
300
    }
1,200✔
301
}
302

303
// builds TransactionProof::SingleProof from Claim, NonDeterminism
304
//
305
// will generate a mock proof if Network::use_mock_proof() is true.
306
async fn gen_single<'a, F>(
70✔
307
    claim: Claim,
70✔
308
    nondeterminism: F,
70✔
309
    job_queue: Arc<TritonVmJobQueue>,
70✔
310
    proof_job_options: TritonVmProofJobOptions,
70✔
311
    valid_mock: bool,
70✔
312
) -> Result<TransactionProof, CreateProofError>
70✔
313
where
70✔
314
    F: FnOnce() -> NonDeterminism + Send + Sync + 'a,
70✔
315
{
70✔
316
    Ok(TransactionProof::SingleProof(
317
        ProofBuilder::new()
70✔
318
            .program(SingleProof.program())
70✔
319
            .claim(claim)
70✔
320
            .nondeterminism(nondeterminism)
70✔
321
            .job_queue(job_queue)
70✔
322
            .proof_job_options(proof_job_options)
70✔
323
            .valid_mock(valid_mock)
70✔
324
            .build()
70✔
325
            .await?,
70✔
326
    ))
327
}
70✔
328

329
// builds TransactionProof from Cow<PrimitiveWitness>
330
//
331
// will generate a mock proof if Network::use_mock_proof() is true.
332
async fn from_witness(
1,130✔
333
    witness_cow: Cow<'_, PrimitiveWitness>,
1,130✔
334
    job_queue: Arc<TritonVmJobQueue>,
1,130✔
335
    proof_job_options: TritonVmProofJobOptions,
1,130✔
336
    valid_mock: bool,
1,130✔
337
) -> Result<TransactionProof, CreateProofError> {
1,130✔
338
    let capability = proof_job_options.job_settings.tx_proving_capability;
1,130✔
339
    let proof_type = proof_job_options.job_settings.proof_type;
1,130✔
340

341
    // generate mock proof, if network uses mock proofs.
342
    if proof_job_options.job_settings.network.use_mock_proof() {
1,130✔
343
        let proof = match proof_type {
109✔
344
            TransactionProofType::PrimitiveWitness => {
345
                TransactionProof::Witness(witness_cow.into_owned())
105✔
346
            }
347
            TransactionProofType::ProofCollection => {
348
                let pc = ProofCollection::produce_mock(witness_cow.borrow(), valid_mock);
×
349
                TransactionProof::ProofCollection(pc)
×
350
            }
351
            TransactionProofType::SingleProof => {
352
                let sp = SingleProof::produce_mock(valid_mock);
4✔
353
                TransactionProof::SingleProof(sp)
4✔
354
            }
355
        };
356
        return Ok(proof);
109✔
357
    }
1,021✔
358

359
    // abort early if machine is too weak
360
    if !capability.can_prove(proof_type) {
1,021✔
361
        return Err(CreateProofError::TooWeak {
×
362
            proof_type,
×
363
            capability,
×
364
        });
×
365
    }
1,021✔
366

367
    // produce proof of requested type
368
    let transaction_proof = match proof_type {
1,021✔
369
        TransactionProofType::PrimitiveWitness => {
370
            TransactionProof::Witness(witness_cow.into_owned())
920✔
371
        }
372
        TransactionProofType::ProofCollection => TransactionProof::ProofCollection(
373
            ProofCollection::produce(witness_cow.borrow(), job_queue, proof_job_options).await?,
21✔
374
        ),
375
        TransactionProofType::SingleProof => TransactionProof::SingleProof(
376
            SingleProof::produce(witness_cow.borrow(), job_queue, proof_job_options).await?,
80✔
377
        ),
378
    };
379

380
    Ok(transaction_proof)
1,018✔
381
}
1,130✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc