Skip to main content

dpp/group/
mod.rs

1use crate::data_contract::group::{Group, GroupMemberPower};
2use crate::data_contract::GroupContractPosition;
3#[cfg(feature = "json-conversion")]
4use crate::serialization::json_safe_fields;
5#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
6use crate::serialization::JsonConvertible;
7#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
8use crate::serialization::ValueConvertible;
9use bincode::{Decode, DecodeUntrusted, Encode};
10use derive_more::Display;
11use platform_value::Identifier;
12#[cfg(feature = "serde-conversion")]
13use serde::{Deserialize, Serialize};
14
15pub mod action_event;
16pub mod action_taker;
17pub mod group_action;
18pub mod group_action_status;
19
20#[derive(Debug, Clone, Copy, Encode, Decode, PartialEq, DecodeUntrusted)]
21pub enum GroupStateTransitionInfoStatus {
22    GroupStateTransitionInfoProposer(GroupContractPosition),
23    GroupStateTransitionInfoOtherSigner(GroupStateTransitionInfo),
24}
25
26impl From<GroupStateTransitionInfoStatus> for GroupStateTransitionInfo {
27    fn from(value: GroupStateTransitionInfoStatus) -> Self {
28        match value {
29            GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(
30                group_contract_position,
31            ) => GroupStateTransitionInfo {
32                group_contract_position,
33                action_id: Default::default(),
34                action_is_proposer: true,
35            },
36            GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => info,
37        }
38    }
39}
40
41#[cfg_attr(feature = "json-conversion", json_safe_fields)]
42#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display, DecodeUntrusted)]
43#[cfg_attr(
44    feature = "serde-conversion",
45    derive(Serialize, Deserialize),
46    serde(rename_all = "camelCase")
47)]
48#[display("ID: {}, Action ID: {}", "id", "action_id")]
49pub struct GroupStateTransitionInfo {
50    #[cfg_attr(feature = "serde-conversion", serde(rename = "$groupContractPosition"))]
51    pub group_contract_position: GroupContractPosition,
52    #[cfg_attr(feature = "serde-conversion", serde(rename = "$groupActionId"))]
53    pub action_id: Identifier,
54    /// This is true if we are the proposer, otherwise we are just voting on a previous action.
55    #[cfg_attr(feature = "serde-conversion", serde(rename = "$groupActionIsProposer"))]
56    pub action_is_proposer: bool,
57}
58
59#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
60impl JsonConvertible for GroupStateTransitionInfo {}
61
62#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
63impl ValueConvertible for GroupStateTransitionInfo {}
64
65#[derive(Debug, Clone, PartialEq)]
66pub struct GroupStateTransitionResolvedInfo {
67    pub group_contract_position: GroupContractPosition,
68    pub group: Group,
69    pub action_id: Identifier,
70    /// This is true if we are the proposer, otherwise we are just voting on a previous action.
71    pub action_is_proposer: bool,
72    pub signer_power: GroupMemberPower,
73}
74
75#[cfg(all(
76    test,
77    feature = "json-conversion",
78    feature = "value-conversion",
79    feature = "serde-conversion"
80))]
81mod json_convertible_tests_groupstatetransitioninfo {
82    use super::*;
83    use platform_value::platform_value;
84    use serde_json::json;
85
86    fn fixture() -> GroupStateTransitionInfo {
87        GroupStateTransitionInfo {
88            group_contract_position: 5,
89            action_id: Identifier::new([0x33; 32]),
90            action_is_proposer: true,
91        }
92    }
93
94    #[test]
95    fn json_round_trip_with_full_wire_shape() {
96        use crate::serialization::JsonConvertible;
97        let original = fixture();
98        let json = original.to_json().expect("to_json");
99        // Each field has an explicit `serde(rename = "$..." )` so the wire keys
100        // are `$groupContractPosition` / `$groupActionId` / `$groupActionIsProposer`.
101        // `group_contract_position` is `GroupContractPosition` (= u16), so JSON
102        // erases the size — the value-path assertion uses `5u16`.
103        // `action_id` is `Identifier` and serializes as base58 in JSON.
104        assert_eq!(
105            json,
106            json!({
107                "$groupContractPosition": 5,
108                "$groupActionId": "4Ss5JMkXAD9Z7cktFEdrqeMuT6jGMF1pVozTyPHZ6zT4",
109                "$groupActionIsProposer": true,
110            })
111        );
112        let recovered = GroupStateTransitionInfo::from_json(json).expect("from_json");
113        assert_eq!(original, recovered);
114    }
115
116    #[test]
117    fn value_round_trip_with_full_wire_shape() {
118        use crate::serialization::ValueConvertible;
119        let original = fixture();
120        let value = original.to_object().expect("to_object");
121        // `5u16` locks `Value::U16`. `Identifier` flows through as
122        // `Value::Identifier` when interpolated into `platform_value!`.
123        let action_id = Identifier::new([0x33; 32]);
124        assert_eq!(
125            value,
126            platform_value!({
127                "$groupContractPosition": 5u16,
128                "$groupActionId": action_id,
129                "$groupActionIsProposer": true,
130            })
131        );
132        let recovered = GroupStateTransitionInfo::from_object(value).expect("from_object");
133        assert_eq!(original, recovered);
134    }
135}