Skip to main content

dpp/asset_lock/
mod.rs

1use crate::asset_lock::reduced_asset_lock_value::AssetLockValue;
2#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
3use crate::serialization::JsonConvertible;
4#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
5use crate::serialization::ValueConvertible;
6
7pub mod reduced_asset_lock_value;
8
9pub type PastAssetLockStateTransitionHashes = Vec<Vec<u8>>;
10
11/// An enumeration of the possible states when querying platform to get the stored state of an outpoint
12/// representing if the asset lock was already used or not.
13#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
14#[serde(tag = "$type")]
15pub enum StoredAssetLockInfo {
16    /// The asset lock was fully consumed in the past
17    FullyConsumed,
18    /// The asset lock was partially consumed, and we stored the asset lock value in the state
19    PartiallyConsumed(AssetLockValue),
20    /// The asset lock is not yet known to Platform
21    NotPresent,
22}
23
24#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
25impl JsonConvertible for StoredAssetLockInfo {}
26
27#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
28impl ValueConvertible for StoredAssetLockInfo {}
29
30#[cfg(all(
31    test,
32    feature = "json-conversion",
33    feature = "value-conversion",
34    feature = "serde-conversion"
35))]
36mod json_convertible_tests {
37    use super::*;
38    use platform_value::{platform_value, Bytes32, Value};
39    use platform_version::version::PlatformVersion;
40    use serde_json::json;
41
42    fn partially_consumed_fixture() -> StoredAssetLockInfo {
43        let asset_lock_value = AssetLockValue::new(
44            1_000_000,
45            vec![0xaa, 0xbb, 0xcc, 0xdd],
46            500_000,
47            vec![Bytes32::new([0x42; 32])],
48            PlatformVersion::latest(),
49        )
50        .expect("fixture");
51        StoredAssetLockInfo::PartiallyConsumed(asset_lock_value)
52    }
53
54    // `StoredAssetLockInfo` is internally tagged (`#[serde(tag = "$type")]`):
55    // unit variants serialize as `{"$type": "FullyConsumed"}`, and the
56    // `PartiallyConsumed` newtype variant flattens its inner `AssetLockValue`
57    // (itself `tag = "$formatVersion"`) up to the same wire level, giving
58    // `{"$type": "PartiallyConsumed", "$formatVersion": "0", ...}`. The `$`
59    // prefix follows the codebase rule: the discriminator is `$`-prefixed when
60    // other `$`-fields (here `$formatVersion`) share the same wire level.
61
62    #[test]
63    fn json_round_trip_fully_consumed() {
64        use crate::serialization::JsonConvertible;
65        let original = StoredAssetLockInfo::FullyConsumed;
66        let json = original.to_json().expect("to_json");
67        assert_eq!(json, json!({ "$type": "FullyConsumed" }));
68        let recovered = StoredAssetLockInfo::from_json(json).expect("from_json");
69        assert_eq!(original, recovered);
70    }
71
72    #[test]
73    fn json_round_trip_not_present() {
74        use crate::serialization::JsonConvertible;
75        let original = StoredAssetLockInfo::NotPresent;
76        let json = original.to_json().expect("to_json");
77        assert_eq!(json, json!({ "$type": "NotPresent" }));
78        let recovered = StoredAssetLockInfo::from_json(json).expect("from_json");
79        assert_eq!(original, recovered);
80    }
81
82    #[test]
83    fn json_round_trip_partially_consumed() {
84        use crate::serialization::JsonConvertible;
85        let original = partially_consumed_fixture();
86        let json = original.to_json().expect("to_json");
87        // Internal `$type` tag sits flat alongside the inner `AssetLockValue`'s
88        // own `$formatVersion` tag (`tag = "$formatVersion"`). `Bytes32` is
89        // base64 in JSON HR, and `tx_out_script` (`Vec<u8>`) is base64 too via
90        // `#[json_safe_fields]`'s `serde_bytes_var` annotation.
91        assert_eq!(
92            json,
93            json!({
94                "$type": "PartiallyConsumed",
95                "$formatVersion": "0",
96                "initial_credit_value": 1_000_000,
97                "tx_out_script": "qrvM3Q==",
98                "remaining_credit_value": 500_000,
99                "used_tags": ["QkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkI="],
100            })
101        );
102        let recovered = StoredAssetLockInfo::from_json(json).expect("from_json");
103        assert_eq!(original, recovered);
104    }
105
106    #[test]
107    fn value_round_trip_fully_consumed() {
108        use crate::serialization::ValueConvertible;
109        let original = StoredAssetLockInfo::FullyConsumed;
110        let value = original.to_object().expect("to_object");
111        assert_eq!(value, platform_value!({ "$type": "FullyConsumed" }));
112        let recovered = StoredAssetLockInfo::from_object(value).expect("from_object");
113        assert_eq!(original, recovered);
114    }
115
116    #[test]
117    fn value_round_trip_not_present() {
118        use crate::serialization::ValueConvertible;
119        let original = StoredAssetLockInfo::NotPresent;
120        let value = original.to_object().expect("to_object");
121        assert_eq!(value, platform_value!({ "$type": "NotPresent" }));
122        let recovered = StoredAssetLockInfo::from_object(value).expect("from_object");
123        assert_eq!(original, recovered);
124    }
125
126    #[test]
127    fn value_round_trip_partially_consumed() {
128        use crate::serialization::ValueConvertible;
129        let original = partially_consumed_fixture();
130        let value = original.to_object().expect("to_object");
131        // `Credits` (u64) → `Value::U64`. `tx_out_script` (`Vec<u8>`) →
132        // `Value::Bytes` via `#[json_safe_fields]`. `used_tags` →
133        // `Array(Vec<Value::Bytes32>)`.
134        assert_eq!(
135            value,
136            platform_value!({
137                "$type": "PartiallyConsumed",
138                "$formatVersion": "0",
139                "initial_credit_value": 1_000_000u64,
140                "tx_out_script": Value::Bytes(vec![0xaa, 0xbb, 0xcc, 0xdd]),
141                "remaining_credit_value": 500_000u64,
142                "used_tags": [Value::Bytes32([0x42; 32])],
143            })
144        );
145        let recovered = StoredAssetLockInfo::from_object(value).expect("from_object");
146        assert_eq!(original, recovered);
147    }
148}