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

ergoplatform / sigma-rust / 16405540612

20 Jul 2025 11:50PM UTC coverage: 78.438% (-0.01%) from 78.451%
16405540612

Pull #790

github

web-flow
Merge 7bd76aff4 into 2725f402c
Pull Request #790: Use precomputed tables

62 of 69 new or added lines in 16 files covered. (89.86%)

10 existing lines in 5 files now uncovered.

11961 of 15249 relevant lines covered (78.44%)

2.94 hits per line

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

82.05
/ergo-lib/src/chain/transaction/unsigned.rs
1
//! Unsigned (without proofs) transaction
2

3
use super::input::UnsignedInput;
4

5
use super::DataInput;
6
use super::Transaction;
7
use super::TxIoVec;
8
use super::{distinct_token_ids, TransactionError};
9
use alloc::vec::Vec;
10
use bounded_vec::BoundedVec;
11
use ergo_chain_types::blake2b256_hash;
12

13
use core::convert::TryInto;
14
use ergotree_ir::chain::ergo_box::ErgoBox;
15
use ergotree_ir::chain::ergo_box::ErgoBoxCandidate;
16
use ergotree_ir::chain::token::TokenId;
17
use ergotree_ir::chain::tx_id::TxId;
18
use ergotree_ir::chain::IndexSet;
19
use ergotree_ir::serialization::SigmaSerializationError;
20

21
/// Unsigned (inputs without proofs) transaction
22
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
23
#[cfg_attr(
24
    feature = "json",
25
    serde(
26
        try_from = "crate::chain::json::transaction::UnsignedTransactionJson",
27
        into = "crate::chain::json::transaction::UnsignedTransactionJson"
28
    )
29
)]
30
#[derive(PartialEq, Eq, Debug, Clone)]
31
pub struct UnsignedTransaction {
32
    tx_id: TxId,
33
    /// unsigned inputs, that will be spent by this transaction.
34
    pub inputs: TxIoVec<UnsignedInput>,
35
    /// inputs, that are not going to be spent by transaction, but will be reachable from inputs
36
    /// scripts. `dataInputs` scripts will not be executed, thus their scripts costs are not
37
    /// included in transaction cost and they do not contain spending proofs.
38
    pub data_inputs: Option<TxIoVec<DataInput>>,
39
    /// box candidates to be created by this transaction
40
    pub output_candidates: TxIoVec<ErgoBoxCandidate>,
41
    pub(crate) outputs: TxIoVec<ErgoBox>,
42
}
43

44
impl UnsignedTransaction {
45
    /// Creates new transaction from vectors
46
    pub fn new_from_vec(
1✔
47
        inputs: Vec<UnsignedInput>,
48
        data_inputs: Vec<DataInput>,
49
        output_candidates: Vec<ErgoBoxCandidate>,
50
    ) -> Result<UnsignedTransaction, TransactionError> {
51
        Ok(UnsignedTransaction::new(
3✔
52
            inputs
2✔
53
                .try_into()
54
                .map_err(TransactionError::InvalidInputsCount)?,
×
55
            BoundedVec::opt_empty_vec(data_inputs)
2✔
56
                .map_err(TransactionError::InvalidDataInputsCount)?,
×
57
            output_candidates
2✔
58
                .try_into()
59
                .map_err(TransactionError::InvalidOutputCandidatesCount)?,
×
60
        )?)
61
    }
62

63
    /// Creates new transaction
64
    pub fn new(
1✔
65
        inputs: TxIoVec<UnsignedInput>,
66
        data_inputs: Option<TxIoVec<DataInput>>,
67
        output_candidates: TxIoVec<ErgoBoxCandidate>,
68
    ) -> Result<UnsignedTransaction, SigmaSerializationError> {
69
        #[allow(clippy::unwrap_used)] // box serialization cannot fail
70
        let outputs = output_candidates
2✔
71
            .iter()
72
            .enumerate()
73
            .map(|(idx, b)| ErgoBox::from_box_candidate(b, TxId::zero(), idx as u16).unwrap())
2✔
74
            .collect::<Vec<_>>()
75
            .try_into()
76
            .unwrap();
77

78
        let tx_to_sign = UnsignedTransaction {
79
            tx_id: TxId::zero(),
1✔
80
            inputs,
81
            data_inputs,
82
            output_candidates,
83
            outputs,
84
        };
85
        let tx_id = tx_to_sign.calc_tx_id()?;
2✔
86

87
        let outputs = tx_to_sign
2✔
88
            .output_candidates
89
            .clone()
90
            .enumerated()
91
            .try_mapped_ref(|(idx, bc)| ErgoBox::from_box_candidate(bc, tx_id, *idx as u16))?;
3✔
92

93
        Ok(UnsignedTransaction {
1✔
94
            tx_id,
1✔
95
            outputs,
1✔
96
            ..tx_to_sign
97
        })
98
    }
99

100
    fn calc_tx_id(&self) -> Result<TxId, SigmaSerializationError> {
1✔
101
        let bytes = self.bytes_to_sign()?;
1✔
102
        Ok(TxId(blake2b256_hash(&bytes)))
2✔
103
    }
104

105
    fn to_tx_without_proofs(&self) -> Result<Transaction, SigmaSerializationError> {
1✔
106
        let empty_proofs_input = self.inputs.mapped_ref(|ui| ui.input_to_sign());
3✔
107
        Transaction::new(
108
            empty_proofs_input,
1✔
109
            self.data_inputs.clone(),
2✔
110
            self.output_candidates.clone(),
1✔
111
        )
112
    }
113

114
    /// Get transaction id
115
    pub fn id(&self) -> TxId {
×
116
        self.tx_id
×
117
    }
118

119
    /// message to be signed by the [`ergotree_interpreter::sigma_protocol::prover::Prover`] (serialized tx)
120
    pub fn bytes_to_sign(&self) -> Result<Vec<u8>, SigmaSerializationError> {
1✔
121
        let tx = self.to_tx_without_proofs()?;
1✔
122
        tx.bytes_to_sign()
1✔
123
    }
124

125
    /// Returns distinct token ids from all output_candidates
126
    pub fn distinct_token_ids(&self) -> IndexSet<TokenId> {
×
NEW
127
        distinct_token_ids(&self.output_candidates)
×
128
    }
129
}
130

131
/// Arbitrary impl
132
#[cfg(feature = "arbitrary")]
133
#[allow(clippy::unwrap_used)]
134
pub mod arbitrary {
135
    use super::*;
136

137
    use proptest::prelude::*;
138
    use proptest::{arbitrary::Arbitrary, collection::vec};
139

140
    impl Arbitrary for UnsignedTransaction {
141
        type Parameters = ();
142

143
        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1✔
144
            (
145
                vec(any::<UnsignedInput>(), 1..10),
1✔
146
                vec(any::<DataInput>(), 0..10),
2✔
147
                vec(any::<ErgoBoxCandidate>(), 1..10),
2✔
148
            )
149
                .prop_map(|(inputs, data_inputs, outputs)| {
2✔
150
                    Self::new_from_vec(inputs, data_inputs, outputs).unwrap()
1✔
151
                })
152
                .boxed()
153
        }
154
        type Strategy = BoxedStrategy<Self>;
155
    }
156
}
157

158
#[cfg(test)]
159
#[allow(clippy::unwrap_used, clippy::panic)]
160
mod tests {
161
    use super::*;
162

163
    use proptest::prelude::*;
164

165
    proptest! {
166

167
        #![proptest_config(ProptestConfig::with_cases(16))]
168

169
        #[test]
170
        fn test_unsigned_tx_bytes_to_sign(v in any::<UnsignedTransaction>()) {
171
            prop_assert!(!v.bytes_to_sign().unwrap().is_empty());
172
        }
173

174
    }
175
}
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

© 2025 Coveralls, Inc