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