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

Neptune-Crypto / neptune-core / 14607972517

23 Apr 2025 01:20AM UTC coverage: 84.99% (+0.5%) from 84.452%
14607972517

push

github

dan-da
test: fix race_condition_with_one_new_block

This test was hanging forever in CI.

There were two problems:

1. The CLI args were using the default auto-detected TxProvingCapability which
results in PrimitiveWitness capability on the CI machine which causes the proof
upgrader job to log an error and return (abort).

2. The test was passing a cloned channel sender to handle_upgrade() then calling
recv() on the receiver prior to dropping the original sender.  So after
handle_upgrade() aborts and returns the test waits for this message which will
never come because handle_upgrade() already dropped that sender.  But the test
is holding the original sender so it never gets dropped.  deadlock.

The fix for (1) is set the CLI args capability to match the capability in each
iteration of the loop [ProofCollection, SingleProof].

The fix for (2) is simply to *move* the sender into handle_upgrade() instead of
cloning it, so that it gets dropped when the fn ends.  THen the recv().await
immediately returns an error because the channel is closed.

6 of 6 new or added lines in 1 file covered. (100.0%)

2475 existing lines in 50 files now uncovered.

54831 of 64515 relevant lines covered (84.99%)

165910.85 hits per line

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

80.37
/src/models/blockchain/type_scripts/mod.rs
1
pub mod known_type_scripts;
2
pub mod native_currency;
3
pub mod native_currency_amount;
4
pub mod time_lock;
5

6
use std::collections::HashMap;
7
use std::hash::Hasher as StdHasher;
8
use std::sync::Arc;
9

10
#[cfg(any(test, feature = "arbitrary-impls"))]
11
use arbitrary::Arbitrary;
12
use get_size2::GetSize;
13
use itertools::Itertools;
14
use serde::Deserialize;
15
use serde::Serialize;
16
use tasm_lib::prelude::Digest;
17
use tasm_lib::triton_vm::prelude::*;
18
use tasm_lib::twenty_first::math::bfield_codec::BFieldCodec;
19

20
use super::transaction::primitive_witness::SaltedUtxos;
21
use super::transaction::transaction_kernel::TransactionKernel;
22
use super::transaction::utxo::Coin;
23
use crate::api::tx_initiation::builder::proof_builder::ProofBuilder;
24
use crate::job_queue::triton_vm::TritonVmJobQueue;
25
use crate::models::blockchain::transaction::validity::neptune_proof::Proof;
26
use crate::models::proof_abstractions::mast_hash::MastHash;
27
use crate::models::proof_abstractions::tasm::program::ConsensusProgram;
28
use crate::models::proof_abstractions::tasm::program::TritonVmProofJobOptions;
29
use crate::Hash;
30

31
pub(crate) trait TypeScript: ConsensusProgram {
32
    type State: BFieldCodec;
33

34
    fn try_decode_state(
11,643✔
35
        &self,
11,643✔
36
        state: &[BFieldElement],
11,643✔
37
    ) -> Result<Box<Self::State>, <Self::State as BFieldCodec>::Error> {
11,643✔
38
        Self::State::decode(state)
11,643✔
39
    }
11,643✔
40

41
    fn matches_coin(&self, coin: &Coin) -> bool {
11,639✔
42
        self.try_decode_state(&coin.state).is_ok() && coin.type_script_hash == self.hash()
11,639✔
43
    }
11,639✔
44
}
45

46
pub(crate) trait TypeScriptWitness {
47
    fn new(
48
        transaction_kernel: TransactionKernel,
49
        salted_input_utxos: SaltedUtxos,
50
        salted_output_utxos: SaltedUtxos,
51
    ) -> Self;
52
    fn transaction_kernel(&self) -> TransactionKernel;
53
    fn salted_input_utxos(&self) -> SaltedUtxos;
54
    fn salted_output_utxos(&self) -> SaltedUtxos;
55
    fn type_script_and_witness(&self) -> TypeScriptAndWitness;
56
    fn type_script_standard_input(&self) -> PublicInput {
3,626✔
57
        PublicInput::new(
3,626✔
58
            [
3,626✔
59
                self.transaction_kernel().mast_hash().reversed().values(),
3,626✔
60
                Hash::hash(&self.salted_input_utxos()).reversed().values(),
3,626✔
61
                Hash::hash(&self.salted_output_utxos()).reversed().values(),
3,626✔
62
            ]
3,626✔
63
            .concat()
3,626✔
64
            .to_vec(),
3,626✔
65
        )
3,626✔
66
    }
3,626✔
67
}
68

69
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, GetSize, BFieldCodec)]
468✔
70
pub struct TypeScriptAndWitness {
71
    pub program: Program,
72
    nd_tokens: Vec<BFieldElement>,
73
    nd_memory: Vec<(BFieldElement, BFieldElement)>,
74
    nd_digests: Vec<Digest>,
75
}
76

77
impl TypeScriptAndWitness {
78
    pub(crate) fn new_with_nondeterminism(program: Program, witness: NonDeterminism) -> Self {
7,931✔
79
        Self {
7,931✔
80
            program,
7,931✔
81
            nd_memory: witness.ram.into_iter().collect(),
7,931✔
82
            nd_tokens: witness.individual_tokens,
7,931✔
83
            nd_digests: witness.digests,
7,931✔
84
        }
7,931✔
85
    }
7,931✔
86

87
    #[cfg(any(test, feature = "arbitrary-impls"))]
88
    pub(crate) fn new_with_tokens(program: Program, tokens: Vec<BFieldElement>) -> Self {
×
89
        Self {
×
90
            program,
×
91
            nd_memory: vec![],
×
92
            nd_tokens: tokens,
×
93
            nd_digests: vec![],
×
UNCOV
94
        }
×
UNCOV
95
    }
×
96

97
    pub(crate) fn nondeterminism(&self) -> NonDeterminism {
313✔
98
        NonDeterminism::new(self.nd_tokens.clone())
313✔
99
            .with_digests(self.nd_digests.clone())
313✔
100
            .with_ram(self.nd_memory.iter().copied().collect::<HashMap<_, _>>())
313✔
101
    }
313✔
102

103
    /// Assuming the type script halts gracefully, prove it.
104
    pub(crate) async fn prove(
228✔
105
        &self,
228✔
106
        txk_mast_hash: Digest,
228✔
107
        salted_inputs_hash: Digest,
228✔
108
        salted_outputs_hash: Digest,
228✔
109
        triton_vm_job_queue: Arc<TritonVmJobQueue>,
228✔
110
        proof_job_options: TritonVmProofJobOptions,
228✔
111
    ) -> anyhow::Result<Proof> {
228✔
112
        let input = [txk_mast_hash, salted_inputs_hash, salted_outputs_hash]
228✔
113
            .into_iter()
228✔
114
            .flat_map(|d| d.reversed().values())
684✔
115
            .collect_vec();
228✔
116
        let claim = Claim::new(self.program.hash()).with_input(input);
228✔
117

228✔
118
        Ok(ProofBuilder::new()
228✔
119
            .program(self.program.clone())
228✔
120
            .claim(claim)
228✔
121
            .nondeterminism(self.nondeterminism())
228✔
122
            .job_queue(triton_vm_job_queue)
228✔
123
            .proof_job_options(proof_job_options)
228✔
124
            .build()
228✔
125
            .await?)
228✔
126
    }
228✔
127
}
128

129
#[cfg(any(test, feature = "arbitrary-impls"))]
130
impl<'a> Arbitrary<'a> for TypeScriptAndWitness {
131
    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
×
132
        let program = Program::arbitrary(u)?;
×
UNCOV
133
        let tokens = Digest::arbitrary(u)?.reversed().values().to_vec();
×
UNCOV
134
        Ok(TypeScriptAndWitness::new_with_tokens(program, tokens))
×
UNCOV
135
    }
×
136
}
137

138
impl std::hash::Hash for TypeScriptAndWitness {
139
    fn hash<H: StdHasher>(&self, state: &mut H) {
×
140
        self.program.instructions.hash(state);
×
141
        self.nd_tokens.hash(state);
×
UNCOV
142
        self.nd_memory.hash(state);
×
UNCOV
143
        self.nd_digests.hash(state);
×
UNCOV
144
    }
×
145
}
146

147
#[cfg(test)]
148
pub(crate) mod test {
149
    use rand::rngs::StdRng;
150
    use rand::Rng;
151
    use rand::SeedableRng;
152

153
    use super::*;
154

155
    impl TypeScriptAndWitness {
156
        pub(crate) fn halts_gracefully(
6✔
157
            &self,
6✔
158
            txk_mast_hash: Digest,
6✔
159
            salted_inputs_hash: Digest,
6✔
160
            salted_outputs_hash: Digest,
6✔
161
        ) -> bool {
6✔
162
            let standard_input = [txk_mast_hash, salted_inputs_hash, salted_outputs_hash]
6✔
163
                .into_iter()
6✔
164
                .flat_map(|d| d.reversed().values().to_vec())
18✔
165
                .collect_vec();
6✔
166
            let public_input = PublicInput::new(standard_input);
6✔
167

6✔
168
            VM::run(self.program.clone(), public_input, self.nondeterminism()).is_ok()
6✔
169
        }
6✔
170

171
        /// Scramble witness data without affecting program. For negative
172
        /// tests.
173
        pub(crate) fn scramble_non_determinism(&mut self, seed: u64) {
5✔
174
            let mut rng: StdRng = SeedableRng::seed_from_u64(seed);
5✔
175

5✔
176
            if !self.nd_tokens.is_empty() {
5✔
UNCOV
177
                let idx = rng.random_range(0..self.nd_tokens.len());
×
UNCOV
178
                self.nd_tokens[idx] = rng.random();
×
179
            }
5✔
180

181
            if !self.nd_memory.is_empty() {
5✔
182
                let idx = rng.random_range(0..self.nd_memory.len());
5✔
183
                let (address, _value) = self.nd_memory[idx];
5✔
184
                self.nd_memory[idx] = (address, rng.random());
5✔
185
            }
5✔
186

187
            if !self.nd_digests.is_empty() {
5✔
188
                let idx = rng.random_range(0..self.nd_digests.len());
5✔
189
                self.nd_digests[idx] = rng.random();
5✔
190
            }
5✔
191
        }
5✔
192
    }
193
}
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