Parcourir la source

working with actual wormhole transactions

Ayush Suresh il y a 5 mois
Parent
commit
f1d6b92c6b

+ 1 - 0
target_chains/stylus/Cargo.lock

@@ -5882,6 +5882,7 @@ version = "0.1.0"
 dependencies = [
  "alloy-primitives 0.7.6",
  "alloy-sol-types 0.7.6",
+ "base64 0.21.7",
  "keccak-const",
  "mini-alloc 0.4.2",
  "motsu",

+ 1 - 0
target_chains/stylus/contracts/wormhole/Cargo.toml

@@ -17,6 +17,7 @@ mini-alloc.workspace = true
 keccak-const.workspace = true
 secp256k1 = { version = "0.31.0", features = ["rand", "recovery"] }
 sha3 = "0.10.8"
+base64 = "0.21"
 
 [dev-dependencies]
 motsu.workspace = true

+ 70 - 11
target_chains/stylus/contracts/wormhole/src/lib.rs

@@ -197,7 +197,8 @@ impl WormholeContract {
         }
 
         let vm = self.parse_vm(&encoded_vm)?;
-        self.verify_vm(&vm)?;
+
+        let verified = self.verify_vm(&vm);
 
         Ok(vm.payload)
     }
@@ -350,8 +351,9 @@ impl WormholeContract {
             }
 
             let guardian_address = guardian_set.keys[signature.guardian_index as usize];
+            let hashed_vm_hash: FixedBytes<32> = FixedBytes::from(keccak256(vm.hash));
 
-            match self.verify_signature(&vm.hash, &signature.signature, guardian_address) {
+            match self.verify_signature(&hashed_vm_hash, &signature.signature, guardian_address) {
                 Ok(true) => {},
                 Ok(false) => return Err(WormholeError::InvalidSignature.into()),
                 Err(e) => return Err(e),
@@ -406,15 +408,8 @@ impl WormholeContract {
 
         let secp = Secp256k1::new();
 
-        let recid = match signature[64].checked_sub(27) {
-            Some(0) => RecoveryId::Zero,
-            Some(1) => RecoveryId::One,
-            Some(2) => RecoveryId::Two,
-            Some(3) => RecoveryId::Three,
-            _ => return Err(WormholeError::InvalidSignature),
-        };
-        // let recid = RecoveryId::try_from(signature[64] as i32).map_err(|_| WormholeError::InvalidSignature)?;
-
+        let recid = RecoveryId::try_from(signature[64] as i32)
+            .map_err(|_| WormholeError::InvalidSignature)?;
         let recoverable_sig = RecoverableSignature::from_compact(&signature[..64], recid)
             .map_err(|_| WormholeError::InvalidSignature)?;
 
@@ -505,11 +500,28 @@ mod tests {
     use core::str::FromStr;
     use secp256k1::{ecdsa::{RecoverableSignature, RecoveryId}, Secp256k1, Message, SecretKey, PublicKey};
     use stylus_sdk::alloy_primitives::keccak256;
+    use base64::engine::general_purpose;
+    use base64::Engine;
 
     const CHAIN_ID: u16 = 60051;
     const GOVERNANCE_CHAIN_ID: u16 = 1;
     const GOVERNANCE_CONTRACT: U256 = U256::from_limbs([4, 0, 0, 0]);
 
+    fn test_real_vaa() -> Vec<u8> {
+        let vaa_raw_base64 = "AQAAAAQNAKPLun8KH+IfCb2c9rlKrXV8wDcZUeMtLeoxoJLHAu7kH40xE1IY5uaJLT4PRsWDDv+7GHNT8rDP+4hUaJNHMtkBAvbQ7aUofV+VAoXjfqrU+V4Vzgvkpwuowaj0BMzNTSp2PkKz5BsnfvC7cxVwOw9sJnQfPvN8KrmhA0IXgQdkQDIBA/0sVNcwZm1oic2G6r7c3x5DyEO9sRF2sTDyM4nuiOtaWPbgolaK6iU3yTx2bEzjdKsdVD2z3qs/QReV8ZxtA5MBBKSm2RKacsgdvwwNZPB3Ifw3P2niCAhZA435PkYeZpDBd8GQ4hALy+42lffR+AXJu19pNs+thWSxq7GRxF5oKz8BBYYS1n9/PJOybDhuWS+PI6YU0CFVTC9pTFSFTlMcEpjsUbT+cUKYCcFU63YaeVGUEPmhFYKeUeRhhQ5g2cCPIegABqts6uHMo5hrdXujJHVEqngLCSaQpB2W9I32LcIvKBfxLcx9IZTjxJ36tyNo7VJ6Fu1FbXnLW0lzaSIbmVmlGukABzpn+9z3bHT6g16HeroSW/YWNlZD5Jo6Zuw9/LT4VD0ET3DgFZtzytkWlJJKAuEB26wRHZbzLAKXfRl+j8kylWQACTTiIiCjZxmEUWjWzWe3JvvPKMNRvYkGkdGaQ7bWVvdiZvxoDq1XHB2H7WnqaAU6xY2pLyf6JG+lV+XZ/GEY+7YBDD/NU/C/gNZP9RP+UujaeJFWt2dau+/g2vtnX/gs2sgBf+yMYm6/dFaT0TiJAcG42zqOi24DLpsdVefaUV1G7CABDjmSRpA//pdAOL5ZxEFG1ia7TnwslsgsvVOa4pKUp5HSZv1JEUO6xMDkTOrBBt5vv9n6zYp3tpYHgUB/fZDh/qUBDzHxNtrQuL/n8a2HOY34yqljpBOCigAbHj+xQmu85u8ieUyge/2zqTn8PYMcka3pW1WTzOAOZf1pLHO+oPEfkTMBEGUS9UOAeY6IUabiEtAQ6qnR47WgPPHYSZUtKBkU0JscDgW0cFq47qmet9OCo79183dRDYE0kFIhnJDk/r7Cq4ABEfBBD83OEF2LJKKkJIBL/KBiD/Mjh3jwKXqqj28EJt1lKCYiGlPhqOCqRArydP94c37MSdrrPlkh0bhcFYs3deMAaEhJXwAAAAAABQAAAAAAAAAAAAAAACdCjdLT3TKk1/fEl+qqIxMNiUkRAAAAAAAEDRXIAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMMN2oOke3QAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABu3yoHkAEAAAAAAAAAAAAAAAAPpLFVLLUvQgzfCF8uDxxgOpZXNaAAAAAAAAAAAAAAAAegpThHd29+lMw1dClxrLIhew24EAAAAAAAAAAAAAAAB6ClOEd3b36UzDV0KXGssiF7DbgQAAAAAAAAAAAAAAACdCjdLT3TKk1/fEl+qqIxMNiUkRAA==";
+        let vaa_bytes = general_purpose::STANDARD.decode(vaa_raw_base64).unwrap();
+        let vaa: Vec<u8> = vaa_bytes;
+        vaa
+    }
+
+    fn create_vaa_bytes(input_string: &str) -> Vec<u8> {
+        let vaa_bytes = general_purpose::STANDARD
+            .decode(input_string)
+            .expect("Failed to decode base64 VAA");
+        let vaa: Vec<u8> = vaa_bytes;
+        vaa
+    }
+
     fn test_guardian_secret1() -> SecretKey {
         SecretKey::from_slice(&[
             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -558,6 +570,15 @@ mod tests {
         contract
     }
 
+    fn deploy_with_real_guardians() -> WormholeContract {
+        let mut contract = WormholeContract::default();
+        let guardians = current_guardians();
+        let governance_contract = Address::from_slice(&GOVERNANCE_CONTRACT.to_be_bytes::<32>()[12..32]);
+        contract.initialize(guardians, CHAIN_ID, GOVERNANCE_CHAIN_ID, governance_contract).unwrap();
+        contract.store_guardian_set(4, current_guardians(), 0);
+        contract
+    }
+
     fn deploy_with_mainnet_guardian_set0() -> WormholeContract {
         let mut contract = WormholeContract::default();
         let guardians = guardian_set0();
@@ -594,6 +615,30 @@ mod tests {
         ]
     }
 
+    fn current_guardians() -> Vec<Address> {
+        vec![
+            Address::from_str("0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3").unwrap(), // Rockaway
+            Address::from_str("0xfF6CB952589BDE862c25Ef4392132fb9D4A42157").unwrap(), // Staked
+            Address::from_str("0x114De8460193bdf3A2fCf81f86a09765F4762fD1").unwrap(), // Figment
+            Address::from_str("0x107A0086b32d7A0977926A205131d8731D39cbEB").unwrap(), // ChainodeTech
+            Address::from_str("0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2").unwrap(), // Inotel
+            Address::from_str("0x11b39756C042441BE6D8650b69b54EbE715E2343").unwrap(), // HashKey Cloud
+            Address::from_str("0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd").unwrap(), // ChainLayer
+            Address::from_str("0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20").unwrap(), // xLabs
+            Address::from_str("0x74a3bf913953D695260D88BC1aA25A4eeE363ef0").unwrap(), // Forbole
+            Address::from_str("0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e").unwrap(), // Staking Fund
+            Address::from_str("0xAF45Ced136b9D9e24903464AE889F5C8a723FC14").unwrap(), // Moonlet Wallet
+            Address::from_str("0xf93124b7c738843CBB89E864c862c38cddCccF95").unwrap(), // P2P Validator
+            Address::from_str("0xD2CC37A4dc036a8D232b48f62cDD4731412f4890").unwrap(), // 01node
+            Address::from_str("0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811").unwrap(), // MCF
+            Address::from_str("0x71AA1BE1D36CaFE3867910F99C09e347899C19C3").unwrap(), // Everstake
+            Address::from_str("0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf").unwrap(), // Chorus One
+            Address::from_str("0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8").unwrap(), // Syncnode
+            Address::from_str("0x5E1487F35515d02A92753504a8D75471b9f49EdB").unwrap(), // Triton
+            Address::from_str("0x6FbEBc898F403E4773E95feB15E80C9A99c8348d").unwrap(), // Staking Facilities
+        ]
+    }
+
     fn corrupted_vm(mut real_data: Vec<u8>, pos: usize, random1: u8, random2: u8) -> Vec<u8> {
         if real_data.len() < 2 {
             return real_data;
@@ -692,6 +737,20 @@ mod tests {
         assert_eq!(WormholeContract::quorum(19), 13);
     }
 
+    #[motsu::test]
+    fn test_real_wormhole_vaa_parsing() {
+        let vaa_vec = test_real_vaa();
+        let result = WormholeContract::parse_vm_static(&vaa_vec).unwrap();
+        assert_eq!(result.signatures.len(), 13)
+    }
+
+    #[motsu::test]
+    fn test_real_guardian_set_real_vaa_verification() {
+        let contract = deploy_with_real_guardians();
+        let test_vaa = create_vaa_bytes("AQAAAAQNABKrA7vVGbeFAN4q6OpjL0zVVs8aPJHPqnj6KuboY755N5i2on/i4nXb2nahbVGDDqj9WV2DgLRdUyqoXL/C6HsBA6l03OVpWBMU5Kjh4a3yn539u/m6ieboUz5D2wAqrt0UHCPgOuXlixoEnYZJ2kTGOT0yqd/grj9g1i9hWkGsi/0BBei0DUXj9iLQ8PQfJGQRWluvvBefZrCi7sIpaN1P10FbABdrFE/Mop+h1n4vHleYqtX1DyD/Hl2CUVPRm+TL6AsABigepLVMC/ybUdI71rW5yKda/DxJ/ZtRa1c7iUOxUnpfENoxwLheaJLMfDVb0bfybkPnbq/UjQ3OjP9LMbb2Y5wBBy1uE/9Pv1nIswbb0H4Q4ej1X7W2vvdWTrt3AmrDPOvYfg3mK+Wae5ifPhCFKas7y2gUfHLm0I7INKTHQ+jjK3oBCjc+jJahqTQu/xPi+kgxvsSwwswoxPEgrd3UsylDbGRMKeEQ8pbB8dP3PzkKThYvVjQ56Vl1+ZZkVf4EzKi7uxIAC03+AG9MIrRsCZenLd8/BwJbr3M1MlIRDAE/JZQctOneEhL0ta0KifLZ8516sfpOLO0j4hyX2JGB7+KhEwaa7rAADOgUbAVn/Od0Mcz5T4Xdu0VJVXbvDcP4WC1vuiKYUuwvHI2lPRwUGEXBinmYuFAzBv5goEO+et71DBPbSocfyAgADUmsnFBn9Sqt1X6QUF3KD8aYb0O7x/w33W/VS+3Bl3JnEjfD8RbDWBmfKhamm6B55g3WytoDz5E+0UfwjMBhEs8BDqxaRg10LY8c2ASx/Ps8UZ8qFYdcQ0liJdfiXxaDMZzwMuQpYr3S+CzartkfaNfRKl4269UtQTxbCHYrnu4XrIMBDzNfMrUQCBQPyYTDsAubNi2AbmAsgrcGHNCquna7ScXaFrYbDrWcxNbXRL20fQ8m7lH1llM3S4UC25smNOino8sBEHDm77bSISVBykPRwfkZdtezi7RGxtFfb0jh1Iu54/pXKyQFjKKOzush9dXGvwCVCeKHL7P+PRT8e+FCxFMFaZEAEVxXoDeizuUQoHG1G+o0MNqT/JS4SfE7SyqZ6VJoezHZIxUFlvqYRufJsGk6FU6OO1zbxdL8evNXIoU0TFHVLwoBaEiioAAAAAAAFYm5HmjQJklWYyvxH4q9IkPKpWxKQsl9m5fq3HG/EHS/AAAAAAAAeRsA3ca06nFfN50X8Ov9vOf/MclvDB12K3Pdhb7X87OIwKs=");
+        let result = contract.parse_and_verify_vm(test_vaa);
+    }
+
     #[motsu::test]
     fn test_get_guardian_set_works() {
         let contract = deploy_with_mainnet_guardian_set0();