iop_coeus_node/operations/
mod.rs

1mod delete;
2mod register;
3mod renew;
4mod start_block;
5mod transfer;
6mod update;
7
8pub use delete::*;
9pub use register::*;
10pub use renew::*;
11pub use start_block::*;
12pub use transfer::*;
13pub use update::*;
14
15use super::*;
16
17pub trait Command {
18    fn execute(self, state: &mut State) -> Result<UndoOperation>;
19}
20
21pub(crate) trait AuthorizedCommand: Command {
22    fn validate_auth(&self, state: &State, pk: &MPublicKey) -> Result<()>;
23}
24
25// TODO this should be pub(crate) but exposing "apply system operations" on wasm required public on short term
26pub trait UndoCommand {
27    fn execute(self, state: &mut State) -> Result<()>;
28}
29
30impl Command for UserOperation {
31    fn execute(self, state: &mut State) -> Result<UndoOperation> {
32        match self {
33            Self::Register(op) => op.execute(state),
34            Self::Update(op) => op.execute(state),
35            Self::Renew(op) => op.execute(state),
36            Self::Transfer(op) => op.execute(state),
37            Self::Delete(op) => op.execute(state),
38        }
39    }
40}
41
42impl AuthorizedCommand for UserOperation {
43    fn validate_auth(&self, state: &State, pk: &MPublicKey) -> Result<()> {
44        match self {
45            Self::Register(op) => op.validate_auth(state, pk),
46            Self::Update(op) => op.validate_auth(state, pk),
47            Self::Renew(op) => op.validate_auth(state, pk),
48            Self::Transfer(op) => op.validate_auth(state, pk),
49            Self::Delete(op) => op.validate_auth(state, pk),
50        }
51    }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
55#[serde(tag = "type", rename_all = "camelCase")]
56pub enum SystemOperation {
57    StartBlock(DoStartBlock),
58}
59
60impl SystemOperation {
61    pub fn start_block(height: BlockHeight) -> Self {
62        SystemOperation::StartBlock(DoStartBlock { height })
63    }
64}
65
66impl Command for SystemOperation {
67    fn execute(self, state: &mut State) -> Result<UndoOperation> {
68        match self {
69            Self::StartBlock(op) => op.execute(state),
70        }
71    }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
75#[serde(untagged)]
76#[allow(clippy::large_enum_variant)] // We do not expect places where we store different variants together
77pub enum Operation {
78    System(SystemOperation),
79    User(UserOperation),
80}
81
82impl Command for Operation {
83    fn execute(self, state: &mut State) -> Result<UndoOperation> {
84        match self {
85            Self::System(op) => op.execute(state),
86            Self::User(op) => op.execute(state),
87        }
88    }
89}
90
91impl From<SystemOperation> for Operation {
92    fn from(op: SystemOperation) -> Self {
93        Self::System(op)
94    }
95}
96
97impl From<UserOperation> for Operation {
98    fn from(op: UserOperation) -> Self {
99        Self::User(op)
100    }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
104#[serde(tag = "type", rename_all = "camelCase")]
105pub enum UndoOperation {
106    StartBlock(UndoStartBlock),
107    Register(Box<UndoRegister>), // This variant is big
108    Update(UndoUpdate),
109    Renew(UndoRenew),
110    Transfer(UndoTransfer),
111    Delete(Box<UndoDelete>), // This variant is big
112}
113
114impl UndoCommand for UndoOperation {
115    fn execute(self, state: &mut State) -> Result<()> {
116        match self {
117            Self::StartBlock(op) => op.execute(state),
118            Self::Register(op) => op.execute(state),
119            Self::Update(op) => op.execute(state),
120            Self::Renew(op) => op.execute(state),
121            Self::Transfer(op) => op.execute(state),
122            Self::Delete(op) => op.execute(state),
123        }
124    }
125}
126
127#[cfg(test)]
128mod test {
129    use super::*;
130
131    #[test]
132    fn serde() {
133        let input = r#"{"type":"register","name":".schema.company","owner":"pszp9HBQY4qrx2yPGqM6biZeLmudJanMK6LXzXzLZGciLYA","subtreePolicies":{},"registrationPolicy":"owner","data":{},"expiresAtHeight":1000}"#;
134        let op: UserOperation = serde_json::from_str(input).unwrap();
135
136        assert!(matches!(op, UserOperation::Register(_)));
137        if let UserOperation::Register(r) = &op {
138            assert_eq!(r.name.to_string(), ".schema.company");
139        }
140
141        let output = serde_json::to_string(&op).unwrap();
142
143        assert_eq!(output, input);
144    }
145}