Parcourir la source

feat(target_chains/starknet): add view methods to wormhole (#1595)

Pavel Strakhov il y a 1 an
Parent
commit
67166bbe97

+ 31 - 3
target_chains/starknet/contracts/src/wormhole.cairo

@@ -3,9 +3,12 @@ mod errors;
 mod governance;
 mod parse_vm;
 
-pub use errors::{GovernanceError, SubmitNewGuardianSetError, ParseAndVerifyVmError};
+pub use errors::{
+    GovernanceError, SubmitNewGuardianSetError, ParseAndVerifyVmError, GetGuardianSetError
+};
 pub use interface::{
-    VerifiedVM, IWormhole, IWormholeDispatcher, IWormholeDispatcherTrait, GuardianSignature, quorum
+    VerifiedVM, IWormhole, IWormholeDispatcher, IWormholeDispatcherTrait, GuardianSignature, quorum,
+    GuardianSet
 };
 pub use wormhole::{Event, GuardianSetAdded};
 
@@ -16,7 +19,7 @@ mod wormhole {
     use core::array::ArrayTrait;
     use super::{
         VerifiedVM, IWormhole, quorum, ParseAndVerifyVmError, SubmitNewGuardianSetError,
-        GovernanceError
+        GovernanceError, GetGuardianSetError
     };
     use super::governance;
     use super::parse_vm::parse_vm;
@@ -122,9 +125,34 @@ mod wormhole {
             vm
         }
 
+        fn get_guardian_set(self: @ContractState, index: u32) -> super::GuardianSet {
+            let mut keys = array![];
+            let set = self.guardian_sets.read(index);
+            if set.num_guardians == 0 {
+                panic_with_felt252(GetGuardianSetError::InvalidIndex.into());
+            }
+            let mut i: u8 = 0;
+            while i.into() < set.num_guardians {
+                keys.append(self.guardian_keys.read((index, i)));
+                i += 1;
+            };
+            super::GuardianSet { keys, expiration_time: set.expiration_time }
+        }
+        fn get_current_guardian_set_index(self: @ContractState) -> u32 {
+            self.current_guardian_set_index.read()
+        }
+        fn governance_action_is_consumed(self: @ContractState, hash: u256) -> bool {
+            self.consumed_governance_actions.read(hash)
+        }
         fn chain_id(self: @ContractState) -> u16 {
             self.chain_id.read()
         }
+        fn governance_chain_id(self: @ContractState) -> u16 {
+            self.governance_chain_id.read()
+        }
+        fn governance_contract(self: @ContractState) -> u256 {
+            self.governance_contract.read()
+        }
 
         fn submit_new_guardian_set(ref self: ContractState, encoded_vm: ByteArray) {
             let vm = self.parse_and_verify_vm(encoded_vm);

+ 13 - 0
target_chains/starknet/contracts/src/wormhole/errors.cairo

@@ -76,3 +76,16 @@ impl ErrorIntoFelt252 of Into<ParseAndVerifyVmError, felt252> {
         }
     }
 }
+
+#[derive(Copy, Drop, Debug, Serde, PartialEq)]
+pub enum GetGuardianSetError {
+    InvalidIndex,
+}
+
+impl GetGuardianSetErrorIntoFelt252 of Into<GetGuardianSetError, felt252> {
+    fn into(self: GetGuardianSetError) -> felt252 {
+        match self {
+            GetGuardianSetError::InvalidIndex => 'invalid index',
+        }
+    }
+}

+ 13 - 0
target_chains/starknet/contracts/src/wormhole/interface.cairo

@@ -1,11 +1,18 @@
 use super::errors::SubmitNewGuardianSetError;
 use pyth::byte_array::ByteArray;
 use core::starknet::secp256_trait::Signature;
+use core::starknet::EthAddress;
 
 #[starknet::interface]
 pub trait IWormhole<T> {
     fn parse_and_verify_vm(self: @T, encoded_vm: ByteArray) -> VerifiedVM;
+
+    fn get_guardian_set(self: @T, index: u32) -> GuardianSet;
+    fn get_current_guardian_set_index(self: @T) -> u32;
+    fn governance_action_is_consumed(self: @T, hash: u256) -> bool;
     fn chain_id(self: @T) -> u16;
+    fn governance_chain_id(self: @T) -> u16;
+    fn governance_contract(self: @T) -> u256;
 
     // We don't need to implement other governance actions for now.
     // Instead of upgrading the Wormhole contract, we can switch to another Wormhole address
@@ -39,3 +46,9 @@ pub fn quorum(num_guardians: usize) -> usize {
     assert(num_guardians < 256, SubmitNewGuardianSetError::TooManyGuardians.into());
     ((num_guardians * 2) / 3) + 1
 }
+
+#[derive(Drop, Debug, Clone, Serde)]
+pub struct GuardianSet {
+    pub keys: Array<EthAddress>,
+    pub expiration_time: u64,
+}

+ 83 - 5
target_chains/starknet/contracts/tests/wormhole.cairo

@@ -12,6 +12,9 @@ use pyth::util::{UnwrapWithFelt252, array_try_into};
 use core::starknet::{ContractAddress, EthAddress};
 use core::panic_with_felt252;
 use super::data;
+use super::wormhole_guardians::{
+    guardian_set0, guardian_set1, guardian_set2, guardian_set3, guardian_set4
+};
 
 #[generate_trait]
 impl DecodeEventHelpers of DecodeEventHelpersTrait {
@@ -37,6 +40,19 @@ fn decode_event(mut event: Event) -> WormholeEvent {
 fn test_parse_and_verify_vm_works() {
     let dispatcher = deploy_with_mainnet_guardians();
     assert!(dispatcher.chain_id() == CHAIN_ID);
+    assert!(dispatcher.governance_chain_id() == GOVERNANCE_CHAIN_ID);
+    assert!(dispatcher.governance_contract() == GOVERNANCE_CONTRACT);
+    assert!(dispatcher.get_current_guardian_set_index() == 4);
+    let hash1 = 107301215816534416941414788869570552056251358022232518071775510605007996627157;
+    assert!(dispatcher.governance_action_is_consumed(hash1));
+    let hash2 = 69383087152252644362837994811527963218617951938616206795754532940371100771846;
+    assert!(dispatcher.governance_action_is_consumed(hash2));
+    let hash3 = 98574986520203705693876007869045870422906099682167905265431258750902697716275;
+    assert!(dispatcher.governance_action_is_consumed(hash3));
+    let hash4 = 108039149047034949008762260417639972218494870245424949643402483285149262098173;
+    assert!(dispatcher.governance_action_is_consumed(hash4));
+    let not_hash4 = 108039149047034949008762260417639972218494870245424949643402483285149262098174;
+    assert!(!dispatcher.governance_action_is_consumed(not_hash4));
 
     let vm = dispatcher.parse_and_verify_vm(data::good_vm1());
     assert!(vm.version == 1);
@@ -95,6 +111,14 @@ fn test_submit_guardian_set_emits_events() {
 
     let mut spy = spy_events(SpyOn::One(dispatcher.contract_address));
 
+    assert!(dispatcher.get_current_guardian_set_index() == 0);
+    let hash1 = 107301215816534416941414788869570552056251358022232518071775510605007996627157;
+    assert!(!dispatcher.governance_action_is_consumed(hash1));
+    let hash2 = 69383087152252644362837994811527963218617951938616206795754532940371100771846;
+    assert!(!dispatcher.governance_action_is_consumed(hash2));
+    let hash3 = 98574986520203705693876007869045870422906099682167905265431258750902697716275;
+    assert!(!dispatcher.governance_action_is_consumed(hash3));
+
     dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade1());
 
     spy.fetch_events();
@@ -105,6 +129,11 @@ fn test_submit_guardian_set_emits_events() {
     let expected = GuardianSetAdded { index: 1 };
     assert!(event == WormholeEvent::GuardianSetAdded(expected));
 
+    assert!(dispatcher.get_current_guardian_set_index() == 1);
+    assert!(dispatcher.governance_action_is_consumed(hash1));
+    assert!(!dispatcher.governance_action_is_consumed(hash2));
+    assert!(!dispatcher.governance_action_is_consumed(hash3));
+
     dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade2());
 
     spy.fetch_events();
@@ -114,6 +143,60 @@ fn test_submit_guardian_set_emits_events() {
     let event = decode_event(event);
     let expected = GuardianSetAdded { index: 2 };
     assert!(event == WormholeEvent::GuardianSetAdded(expected));
+
+    assert!(dispatcher.get_current_guardian_set_index() == 2);
+    assert!(dispatcher.governance_action_is_consumed(hash1));
+    assert!(dispatcher.governance_action_is_consumed(hash2));
+    assert!(!dispatcher.governance_action_is_consumed(hash3));
+}
+
+#[test]
+fn test_get_guardian_set_works() {
+    let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
+
+    let set0 = dispatcher.get_guardian_set(0);
+    assert!(set0.keys == guardian_set0());
+    assert!(set0.expiration_time == 0);
+    assert!(dispatcher.get_current_guardian_set_index() == 0);
+
+    dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade1());
+    let set0 = dispatcher.get_guardian_set(0);
+    assert!(set0.keys == guardian_set0());
+    assert!(set0.expiration_time != 0);
+    let set1 = dispatcher.get_guardian_set(1);
+    assert!(set1.keys == guardian_set1());
+    assert!(set1.expiration_time == 0);
+    assert!(dispatcher.get_current_guardian_set_index() == 1);
+
+    dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade2());
+    let set0 = dispatcher.get_guardian_set(0);
+    assert!(set0.keys == guardian_set0());
+    assert!(set0.expiration_time != 0);
+    let set1 = dispatcher.get_guardian_set(1);
+    assert!(set1.keys == guardian_set1());
+    assert!(set1.expiration_time != 0);
+    let set2 = dispatcher.get_guardian_set(2);
+    assert!(set2.keys == guardian_set2());
+    assert!(set2.expiration_time == 0);
+    assert!(dispatcher.get_current_guardian_set_index() == 2);
+
+    dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade3());
+    dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade4());
+    let set3 = dispatcher.get_guardian_set(3);
+    assert!(set3.keys == guardian_set3());
+    assert!(set3.expiration_time != 0);
+    let set4 = dispatcher.get_guardian_set(4);
+    assert!(set4.keys == guardian_set4());
+    assert!(set4.expiration_time == 0);
+    assert!(dispatcher.get_current_guardian_set_index() == 4);
+}
+
+#[test]
+#[should_panic(expected: ('invalid index',))]
+fn test_get_guardian_set_rejects_invalid_index() {
+    let dispatcher = deploy(guardian_set0(), CHAIN_ID, GOVERNANCE_CHAIN_ID, GOVERNANCE_CONTRACT);
+    dispatcher.submit_new_guardian_set(data::mainnet_guardian_set_upgrade1());
+    dispatcher.get_guardian_set(2);
 }
 
 #[test]
@@ -299,11 +382,6 @@ fn corrupted_byte(value: u8, random: usize) -> u8 {
     (v % 256).try_into().unwrap()
 }
 
-// Initial mainnet guardian set.
-fn guardian_set0() -> Array<EthAddress> {
-    array_try_into(array![0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5])
-}
-
 pub const CHAIN_ID: u16 = 60051;
 pub const GOVERNANCE_CHAIN_ID: u16 = 1;
 pub const GOVERNANCE_CONTRACT: u256 = 4;

+ 110 - 0
target_chains/starknet/contracts/tests/wormhole_guardians.cairo

@@ -0,0 +1,110 @@
+use pyth::util::array_try_into;
+use core::starknet::EthAddress;
+
+// Initial mainnet guardian set.
+pub fn guardian_set0() -> Array<EthAddress> {
+    let keys = array![0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5];
+    array_try_into(keys)
+}
+
+// Below are actual guardian keys from
+// https://github.com/wormhole-foundation/wormhole-networks/tree/master/mainnetv2/guardianset
+pub fn guardian_set1() -> Array<EthAddress> {
+    let keys = array![
+        0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
+        0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
+        0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
+        0x107A0086b32d7A0977926A205131d8731D39cbEB,
+        0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
+        0x11b39756C042441BE6D8650b69b54EbE715E2343,
+        0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
+        0xeB5F7389Fa26941519f0863349C223b73a6DDEE7,
+        0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
+        0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
+        0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
+        0xf93124b7c738843CBB89E864c862c38cddCccF95,
+        0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
+        0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
+        0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
+        0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
+        0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
+        0x5E1487F35515d02A92753504a8D75471b9f49EdB,
+        0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
+    ];
+    array_try_into(keys)
+}
+
+pub fn guardian_set2() -> Array<EthAddress> {
+    let keys = array![
+        0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
+        0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
+        0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
+        0x107A0086b32d7A0977926A205131d8731D39cbEB,
+        0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
+        0x11b39756C042441BE6D8650b69b54EbE715E2343,
+        0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
+        0x66B9590e1c41e0B226937bf9217D1d67Fd4E91F5,
+        0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
+        0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
+        0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
+        0xf93124b7c738843CBB89E864c862c38cddCccF95,
+        0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
+        0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
+        0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
+        0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
+        0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
+        0x5E1487F35515d02A92753504a8D75471b9f49EdB,
+        0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
+    ];
+    array_try_into(keys)
+}
+
+pub fn guardian_set3() -> Array<EthAddress> {
+    let keys = array![
+        0x58CC3AE5C097b213cE3c81979e1B9f9570746AA5,
+        0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
+        0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
+        0x107A0086b32d7A0977926A205131d8731D39cbEB,
+        0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
+        0x11b39756C042441BE6D8650b69b54EbE715E2343,
+        0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
+        0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20,
+        0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
+        0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
+        0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
+        0xf93124b7c738843CBB89E864c862c38cddCccF95,
+        0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
+        0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
+        0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
+        0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
+        0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
+        0x5E1487F35515d02A92753504a8D75471b9f49EdB,
+        0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
+    ];
+    array_try_into(keys)
+}
+
+pub fn guardian_set4() -> Array<EthAddress> {
+    let keys = array![
+        0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3,
+        0xfF6CB952589BDE862c25Ef4392132fb9D4A42157,
+        0x114De8460193bdf3A2fCf81f86a09765F4762fD1,
+        0x107A0086b32d7A0977926A205131d8731D39cbEB,
+        0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2,
+        0x11b39756C042441BE6D8650b69b54EbE715E2343,
+        0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd,
+        0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20,
+        0x74a3bf913953D695260D88BC1aA25A4eeE363ef0,
+        0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e,
+        0xAF45Ced136b9D9e24903464AE889F5C8a723FC14,
+        0xf93124b7c738843CBB89E864c862c38cddCccF95,
+        0xD2CC37A4dc036a8D232b48f62cDD4731412f4890,
+        0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811,
+        0x71AA1BE1D36CaFE3867910F99C09e347899C19C3,
+        0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf,
+        0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8,
+        0x5E1487F35515d02A92753504a8D75471b9f49EdB,
+        0x6FbEBc898F403E4773E95feB15E80C9A99c8348d,
+    ];
+    array_try_into(keys)
+}