iota_bridge/server/
governance_verifier.rs1use std::collections::HashMap;
6
7use crate::{
8 error::{BridgeError, BridgeResult},
9 server::handler::ActionVerifier,
10 types::{BridgeAction, BridgeActionDigest},
11};
12
13#[derive(Debug)]
14pub struct GovernanceVerifier {
15 approved_governance_actions: HashMap<BridgeActionDigest, BridgeAction>,
16}
17
18impl GovernanceVerifier {
19 pub fn new(approved_actions: Vec<BridgeAction>) -> BridgeResult<Self> {
20 let mut approved_governance_actions = HashMap::new();
22 for action in approved_actions {
23 if !action.is_governace_action() {
24 return Err(BridgeError::ActionIsNotGovernanceAction(action));
25 }
26 approved_governance_actions.insert(action.digest(), action);
27 }
28 Ok(Self {
29 approved_governance_actions,
30 })
31 }
32}
33
34#[async_trait::async_trait]
35impl ActionVerifier<BridgeAction> for GovernanceVerifier {
36 fn name(&self) -> &'static str {
37 "GovernanceVerifier"
38 }
39
40 async fn verify(&self, key: BridgeAction) -> BridgeResult<BridgeAction> {
41 if !key.is_governace_action() {
44 return Err(BridgeError::ActionIsNotGovernanceAction(key));
45 }
46 if let Some(approved_action) = self.approved_governance_actions.get(&key.digest()) {
47 assert_eq!(
48 &key, approved_action,
49 "Mismatched action found in approved_actions"
50 );
51 return Ok(key);
52 }
53 return Err(BridgeError::GovernanceActionIsNotApproved);
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use iota_types::bridge::BridgeChainId;
60
61 use super::*;
62 use crate::{
63 test_utils::get_test_iota_to_eth_bridge_action,
64 types::{BridgeAction, EmergencyAction, EmergencyActionType, LimitUpdateAction},
65 };
66
67 #[tokio::test]
68 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
69 async fn test_governance_verifier() {
70 let action_1 = BridgeAction::EmergencyAction(EmergencyAction {
71 chain_id: BridgeChainId::EthCustom,
72 nonce: 1,
73 action_type: EmergencyActionType::Pause,
74 });
75 let action_2 = BridgeAction::LimitUpdateAction(LimitUpdateAction {
76 chain_id: BridgeChainId::EthCustom,
77 sending_chain_id: BridgeChainId::IotaCustom,
78 nonce: 1,
79 new_usd_limit: 10000,
80 });
81
82 let verifier = GovernanceVerifier::new(vec![action_1.clone(), action_2.clone()]).unwrap();
83 assert_eq!(
84 verifier.verify(action_1.clone()).await.unwrap(),
85 action_1.clone()
86 );
87 assert_eq!(
88 verifier.verify(action_2.clone()).await.unwrap(),
89 action_2.clone()
90 );
91
92 let action_3 = BridgeAction::LimitUpdateAction(LimitUpdateAction {
93 chain_id: BridgeChainId::EthCustom,
94 sending_chain_id: BridgeChainId::IotaCustom,
95 nonce: 2,
96 new_usd_limit: 10000,
97 });
98 assert_eq!(
99 verifier.verify(action_3).await.unwrap_err(),
100 BridgeError::GovernanceActionIsNotApproved
101 );
102
103 let action_4 = get_test_iota_to_eth_bridge_action(None, None, None, None, None, None, None);
105 assert!(matches!(
106 GovernanceVerifier::new(vec![action_1, action_2, action_4.clone()]).unwrap_err(),
107 BridgeError::ActionIsNotGovernanceAction(..)
108 ));
109
110 assert!(matches!(
112 verifier.verify(action_4).await.unwrap_err(),
113 BridgeError::ActionIsNotGovernanceAction(..)
114 ));
115 }
116}