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

ergoplatform / sigma-rust / 19909456309

03 Dec 2025 09:29PM UTC coverage: 86.947% (+8.5%) from 78.463%
19909456309

Pull #838

github

web-flow
Merge 717ebc4b7 into 2f840d387
Pull Request #838: Fix CI, bump dependencies and rust toolchain

20 of 24 new or added lines in 12 files covered. (83.33%)

1614 existing lines in 221 files now uncovered.

27478 of 31603 relevant lines covered (86.95%)

506307.07 hits per line

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

96.4
/ergo-lib/src/chain/json/transaction.rs
1
use alloc::string::String;
2
use alloc::vec::Vec;
3
use core::convert::TryFrom;
4
use thiserror::Error;
5

6
use crate::chain::transaction::unsigned::UnsignedTransaction;
7
use crate::chain::transaction::{DataInput, Input, Transaction, TransactionError, UnsignedInput};
8
use ergotree_ir::chain::ergo_box::ErgoBox;
9
use ergotree_ir::chain::ergo_box::ErgoBoxCandidate;
10
use ergotree_ir::chain::tx_id::TxId;
11
use serde::{Deserialize, Serialize};
12

13
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
14
pub struct TransactionJson {
15
    #[cfg_attr(feature = "json", serde(rename = "id"))]
16
    pub tx_id: TxId,
17
    /// inputs, that will be spent by this transaction.
18
    #[cfg_attr(feature = "json", serde(rename = "inputs"))]
19
    pub inputs: Vec<Input>,
20
    /// inputs, that are not going to be spent by transaction, but will be reachable from inputs
21
    /// scripts. `dataInputs` scripts will not be executed, thus their scripts costs are not
22
    /// included in transaction cost and they do not contain spending proofs.
23
    #[cfg_attr(feature = "json", serde(rename = "dataInputs"))]
24
    pub data_inputs: Vec<DataInput>,
25
    #[cfg_attr(feature = "json", serde(rename = "outputs"))]
26
    pub outputs: Vec<ErgoBox>,
27
}
28

29
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
30
pub struct UnsignedTransactionJson {
31
    /// unsigned inputs, that will be spent by this transaction.
32
    #[cfg_attr(feature = "json", serde(rename = "inputs"))]
33
    pub inputs: Vec<UnsignedInput>,
34
    /// inputs, that are not going to be spent by transaction, but will be reachable from inputs
35
    /// scripts. `dataInputs` scripts will not be executed, thus their scripts costs are not
36
    /// included in transaction cost and they do not contain spending proofs.
37
    #[cfg_attr(feature = "json", serde(rename = "dataInputs"))]
38
    pub data_inputs: Vec<DataInput>,
39
    /// box candidates to be created by this transaction
40
    #[cfg_attr(feature = "json", serde(rename = "outputs"))]
41
    pub outputs: Vec<ErgoBoxCandidate>,
42
}
43

44
impl From<UnsignedTransaction> for UnsignedTransactionJson {
45
    fn from(v: UnsignedTransaction) -> Self {
128✔
46
        UnsignedTransactionJson {
47
            inputs: v.inputs.as_vec().clone(),
128✔
48
            data_inputs: v
128✔
49
                .data_inputs
128✔
50
                .map(|di| di.as_vec().clone())
128✔
51
                .unwrap_or_default(),
128✔
52
            outputs: v.output_candidates.as_vec().clone(),
128✔
53
        }
54
    }
128✔
55
}
56

57
impl TryFrom<UnsignedTransactionJson> for UnsignedTransaction {
58
    // We never return this type but () fails to compile (can't format) and ! is experimental
59
    type Error = String;
60
    fn try_from(tx_json: UnsignedTransactionJson) -> Result<Self, Self::Error> {
128✔
61
        UnsignedTransaction::new_from_vec(tx_json.inputs, tx_json.data_inputs, tx_json.outputs)
128✔
62
            .map_err(|e| format!("TryFrom<UnsignedTransactionJson> error: {0:?}", e))
128✔
63
    }
128✔
64
}
65

66
impl From<Transaction> for TransactionJson {
67
    fn from(v: Transaction) -> Self {
130✔
68
        TransactionJson {
69
            tx_id: v.id(),
130✔
70
            inputs: v.inputs.as_vec().clone(),
130✔
71
            data_inputs: v
130✔
72
                .data_inputs
130✔
73
                .map(|di| di.as_vec().clone())
130✔
74
                .unwrap_or_default(),
130✔
75
            outputs: v.outputs.to_vec(),
130✔
76
        }
77
    }
130✔
78
}
79

80
/// Errors on parsing Transaction from JSON
81
#[derive(Error, PartialEq, Eq, Debug, Clone)]
82
#[allow(missing_docs)]
83
pub enum TransactionFromJsonError {
84
    #[error(
85
        "Tx id parsed from JSON {expected} differs from calculated from serialized bytes {actual}"
86
    )]
87
    InvalidTxId { expected: TxId, actual: TxId },
88
    #[error("Tx error: {0}")]
89
    TransactionError(#[from] TransactionError),
90
}
91

92
impl TryFrom<TransactionJson> for Transaction {
93
    type Error = TransactionFromJsonError;
94
    fn try_from(tx_json: TransactionJson) -> Result<Self, Self::Error> {
140✔
95
        let output_candidates: Vec<ErgoBoxCandidate> =
140✔
96
            tx_json.outputs.iter().map(|o| o.clone().into()).collect();
660✔
97
        let tx = Transaction::new_from_vec(tx_json.inputs, tx_json.data_inputs, output_candidates)?;
140✔
98
        if tx.tx_id == tx_json.tx_id {
140✔
99
            Ok(tx)
140✔
100
        } else {
101
            //dbg!(&tx);
102
            Err(TransactionFromJsonError::InvalidTxId {
×
103
                expected: tx_json.tx_id,
×
104
                actual: tx.tx_id,
×
UNCOV
105
            })
×
106
        }
107
    }
140✔
108
}
109

110
#[cfg(test)]
111
#[allow(clippy::panic, clippy::unwrap_used)]
112
mod tests {
113
    use crate::chain::transaction::unsigned::UnsignedTransaction;
114
    use crate::chain::transaction::Transaction;
115
    use ergo_chain_types::Digest32;
116
    use proptest::prelude::*;
117

118
    proptest! {
119

120
        #![proptest_config(ProptestConfig::with_cases(64))]
121

122
        #[test]
123
        fn tx_roundtrip(t in any::<Transaction>()) {
124
            let j = serde_json::to_string(&t)?;
125
            eprintln!("{}", j);
126
            let t_parsed: Transaction = serde_json::from_str(&j)?;
127
            prop_assert_eq![t, t_parsed];
128
        }
129

130
        #[test]
131
        fn unsigned_tx_roundtrip(t in any::<UnsignedTransaction>()) {
132
            let j = serde_json::to_string(&t)?;
133
            eprintln!("{}", j);
134
            let t_parsed: UnsignedTransaction = serde_json::from_str(&j)?;
135
            prop_assert_eq![t, t_parsed];
136
        }
137

138
    }
139

140
    #[test]
141
    fn item_order_preservation_685() {
2✔
142
        let tx_json = r#"
2✔
143
{
2✔
144
        "id" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
2✔
145
        "inputs" : [
2✔
146
          {
2✔
147
            "boxId" : "59f2856068c56264d290520043044ace138a3a80d414748d0e4dcd0806188546",
2✔
148
            "spendingProof" : {
2✔
149
              "proofBytes" : "",
2✔
150
              "extension" : {
2✔
151
                "0" : "04c60f",
2✔
152
                "5" : "0514",
2✔
153
                "10" : "0eee03101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
2✔
154
                "1" : "0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d0",
2✔
155
                "6" : "0580ade204",
2✔
156
                "9" : "0580b48913",
2✔
157
                "2" : "05e201",
2✔
158
                "7" : "0e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f",
2✔
159
                "3" : "05e0e0a447",
2✔
160
                "8" : "0580ade204",
2✔
161
                "4" : "058c85a201"
2✔
162
              }
2✔
163
            }
2✔
164
          }
2✔
165
        ],
2✔
166
        "dataInputs" : [
2✔
167
        ],
2✔
168
        "outputs" : [
2✔
169
          {
2✔
170
            "boxId" : "0586c90d0cf6a82dab48c6a79500364ddbd6f81705f5032b03aa287de43dc638",
2✔
171
            "value" : 94750000,
2✔
172
            "ergoTree" : "101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
2✔
173
            "assets" : [
2✔
174
            ],
2✔
175
            "creationHeight" : 693475,
2✔
176
            "additionalRegisters" : {
2✔
177

2✔
178
            },
2✔
179
            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
2✔
180
            "index" : 0
2✔
181
          },
2✔
182
          {
2✔
183
            "boxId" : "4b99c2ef8496a491d176ecaf789d9e1d9aad0c2bf3e70b32e8bad73f48c722b9",
2✔
184
            "value" : 250000,
2✔
185
            "ergoTree" : "100e04000500059a0505d00f04020404040608cd03c6543ac8e8059748b1c6209ee419dd49a19ffaf5712a2f34a9412016a3a1d96708cd035b736bebf0c5393f78329f6894af84d1864c7496cc65ddc250ef60cdd75df52008cd021b63e19ab452c84cdc6687242e8494957b1f11e3750c8c184a8425f8a8171d9b05060580ade2040580a8d6b907040ad806d601b2a5730000d602b0a47301d9010241639a8c720201c18c720202d6039d9c730272027303d604b2a5730400d605b2a5730500d606b2a5730600d1968306019683020193c17201720393c27201d073079683020193c17204720393c27204d073089683020193c17205720393c27205d073099683020192c17206999972029c730a7203730b93c2a7c27206927202730c93b1a5730d",
2✔
186
            "assets" : [
2✔
187
            ],
2✔
188
            "creationHeight" : 693475,
2✔
189
            "additionalRegisters" : {
2✔
190

2✔
191
            },
2✔
192
            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
2✔
193
            "index" : 1
2✔
194
          },
2✔
195
          {
2✔
196
            "boxId" : "00ddbeb981c0b08536f72ea41e07a25adbf7bf104ee59b865619a21676e64715",
2✔
197
            "value" : 5000000,
2✔
198
            "ergoTree" : "1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304",
2✔
199
            "assets" : [
2✔
200
            ],
2✔
201
            "creationHeight" : 693475,
2✔
202
            "additionalRegisters" : {
2✔
203

2✔
204
            },
2✔
205
            "transactionId" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
2✔
206
            "index" : 2
2✔
207
          }
2✔
208
        ],
2✔
209
        "size" : 1562
2✔
210
      }
2✔
211
    "#;
2✔
212
        let tx: Transaction = serde_json::from_str(tx_json).unwrap();
2✔
213
        assert_eq!(
2✔
214
            tx.id(),
2✔
215
            Digest32::try_from(
2✔
216
                "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4".to_string()
2✔
217
            )
218
            .unwrap()
2✔
219
            .into()
2✔
220
        );
221
    }
2✔
222
}
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