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

ergoplatform / sigma-rust / 19957094785

05 Dec 2025 08:23AM UTC coverage: 86.918% (+8.5%) from 78.463%
19957094785

Pull #837

github

web-flow
Merge dec08367a into 2f840d387
Pull Request #837: Split TransactionHintsBag hints properly

44 of 53 new or added lines in 13 files covered. (83.02%)

1621 existing lines in 221 files now uncovered.

27453 of 31585 relevant lines covered (86.92%)

253204.4 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 {
64✔
46
        UnsignedTransactionJson {
47
            inputs: v.inputs.as_vec().clone(),
64✔
48
            data_inputs: v
64✔
49
                .data_inputs
64✔
50
                .map(|di| di.as_vec().clone())
64✔
51
                .unwrap_or_default(),
64✔
52
            outputs: v.output_candidates.as_vec().clone(),
64✔
53
        }
54
    }
64✔
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> {
64✔
61
        UnsignedTransaction::new_from_vec(tx_json.inputs, tx_json.data_inputs, tx_json.outputs)
64✔
62
            .map_err(|e| format!("TryFrom<UnsignedTransactionJson> error: {0:?}", e))
64✔
63
    }
64✔
64
}
65

66
impl From<Transaction> for TransactionJson {
67
    fn from(v: Transaction) -> Self {
65✔
68
        TransactionJson {
69
            tx_id: v.id(),
65✔
70
            inputs: v.inputs.as_vec().clone(),
65✔
71
            data_inputs: v
65✔
72
                .data_inputs
65✔
73
                .map(|di| di.as_vec().clone())
65✔
74
                .unwrap_or_default(),
65✔
75
            outputs: v.outputs.to_vec(),
65✔
76
        }
77
    }
65✔
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> {
70✔
95
        let output_candidates: Vec<ErgoBoxCandidate> =
70✔
96
            tx_json.outputs.iter().map(|o| o.clone().into()).collect();
310✔
97
        let tx = Transaction::new_from_vec(tx_json.inputs, tx_json.data_inputs, output_candidates)?;
70✔
98
        if tx.tx_id == tx_json.tx_id {
70✔
99
            Ok(tx)
70✔
100
        } else {
101
            //dbg!(&tx);
102
            Err(TransactionFromJsonError::InvalidTxId {
×
103
                expected: tx_json.tx_id,
×
104
                actual: tx.tx_id,
×
UNCOV
105
            })
×
106
        }
107
    }
70✔
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() {
1✔
142
        let tx_json = r#"
1✔
143
{
1✔
144
        "id" : "c8520befd345ff40fcf244b44ffe8cea29c8b116b174cfaf4f2a521604d531a4",
1✔
145
        "inputs" : [
1✔
146
          {
1✔
147
            "boxId" : "59f2856068c56264d290520043044ace138a3a80d414748d0e4dcd0806188546",
1✔
148
            "spendingProof" : {
1✔
149
              "proofBytes" : "",
1✔
150
              "extension" : {
1✔
151
                "0" : "04c60f",
1✔
152
                "5" : "0514",
1✔
153
                "10" : "0eee03101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
1✔
154
                "1" : "0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d0",
1✔
155
                "6" : "0580ade204",
1✔
156
                "9" : "0580b48913",
1✔
157
                "2" : "05e201",
1✔
158
                "7" : "0e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f",
1✔
159
                "3" : "05e0e0a447",
1✔
160
                "8" : "0580ade204",
1✔
161
                "4" : "058c85a201"
1✔
162
              }
1✔
163
            }
1✔
164
          }
1✔
165
        ],
1✔
166
        "dataInputs" : [
1✔
167
        ],
1✔
168
        "outputs" : [
1✔
169
          {
1✔
170
            "boxId" : "0586c90d0cf6a82dab48c6a79500364ddbd6f81705f5032b03aa287de43dc638",
1✔
171
            "value" : 94750000,
1✔
172
            "ergoTree" : "101808cd0279aed8dea2b2a25316d5d49d13bf51c0b2c1dc696974bb4b0c07b5894e998e56040005e0e0a447040404060402040004000e201d5afc59838920bb5ef2a8f9d63825a55b1d48e269d7cecee335d637c3ff5f3f0e20003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d005e201058c85a2010514040404c60f06010104d00f05e0e0a44704c60f0e691005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304050005000580ade2040100d803d6017300d602b2a4730100d6037302eb027201d195ed93b1a4730393b1db630872027304d804d604db63087202d605b2a5730500d606b2db63087205730600d6077e8c72060206edededededed938cb2720473070001730893c27205d07201938c72060173099272077e730a06927ec172050699997ec1a7069d9c72077e730b067e730c067e720306909c9c7e8cb27204730d0002067e7203067e730e069c9a7207730f9a9c7ec17202067e7310067e9c73117e7312050690b0ada5d90108639593c272087313c1720873147315d90108599a8c7208018c72080273167317",
1✔
173
            "assets" : [
1✔
174
            ],
1✔
175
            "creationHeight" : 693475,
1✔
176
            "additionalRegisters" : {
1✔
177

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

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

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