Ver código fonte

[cosmwasm] implement contract version (#730)

* remove depreceated config

* add a contract version

* check valid instantiation

* up a version and generate schema

* update contract upgrade code
Dev Kalra 2 anos atrás
pai
commit
0b9f1f161d

+ 1 - 1
target_chains/cosmwasm/Cargo.lock

@@ -1251,7 +1251,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-cosmwasm"
-version = "1.0.0"
+version = "1.1.0"
 dependencies = [
  "bigint",
  "byteorder",

+ 1 - 1
target_chains/cosmwasm/contracts/pyth/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "pyth-cosmwasm"
-version = "1.0.0"
+version = "1.1.0"
 authors = ["Wormhole Contributors <contact@certus.one>"]
 edition = "2018"
 description = "Pyth price receiver"

+ 2 - 1
target_chains/cosmwasm/contracts/pyth/schema/pyth-cosmwasm.json

@@ -1,6 +1,6 @@
 {
   "contract_name": "pyth-cosmwasm",
-  "contract_version": "0.1.0",
+  "contract_version": "1.1.0",
   "idl_version": "1.0.0",
   "instantiate": {
     "$schema": "http://json-schema.org/draft-07/schema#",
@@ -72,6 +72,7 @@
         }
       },
       "PythDataSource": {
+        "description": "A `PythDataSource` identifies a specific contract (given by its Wormhole `emitter`) on a specific blockchain (given by `chain_id`).",
         "type": "object",
         "required": ["chain_id", "emitter"],
         "properties": {

+ 83 - 29
target_chains/cosmwasm/contracts/pyth/src/contract.rs

@@ -26,10 +26,9 @@ use {
         state::{
             config,
             config_read,
-            deprecated_config,
-            deprecated_config_read,
             price_feed_bucket,
             price_feed_read_bucket,
+            set_contract_version,
             ConfigInfo,
             PythDataSource,
         },
@@ -51,7 +50,6 @@ use {
         OverflowOperation,
         QueryRequest,
         Response,
-        StdError,
         StdResult,
         WasmMsg,
         WasmQuery,
@@ -82,6 +80,8 @@ use {
     },
 };
 
+const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
+
 /// Migration code that runs once when the contract is upgraded. On upgrade, the migrate
 /// function in the *new* code version is run, which allows the new code to update the on-chain
 /// state before any of its other functions are invoked.
@@ -94,29 +94,9 @@ use {
 /// `Ok(Response::default())`
 #[cfg_attr(not(feature = "library"), entry_point)]
 pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
-    let depreceated_cfg_result = deprecated_config_read(deps.storage).load();
-    match depreceated_cfg_result {
-        Ok(depreceated_cfg) => {
-            let cfg = ConfigInfo {
-                wormhole_contract:          depreceated_cfg.wormhole_contract,
-                data_sources:               depreceated_cfg.data_sources,
-                governance_source:          depreceated_cfg.governance_source,
-                governance_source_index:    depreceated_cfg.governance_source_index,
-                governance_sequence_number: depreceated_cfg.governance_sequence_number,
-                chain_id:                   depreceated_cfg.chain_id,
-                valid_time_period:          depreceated_cfg.valid_time_period,
-                fee:                        depreceated_cfg.fee,
-            };
-
-            config(deps.storage).save(&cfg)?;
-            deprecated_config(deps.storage).remove();
-
-            Ok(Response::default())
-        }
-        Err(_) => Err(StdError::GenericErr {
-            msg: String::from("Error reading config"),
-        }),
-    }
+    // a new contract version should be set everytime a contract is migrated
+    set_contract_version(deps.storage, &String::from(CONTRACT_VERSION))?;
+    Ok(Response::default().add_attribute("Contract Version", CONTRACT_VERSION))
 }
 
 #[cfg_attr(not(feature = "library"), entry_point)]
@@ -139,6 +119,8 @@ pub fn instantiate(
     };
     config(deps.storage).save(&state)?;
 
+    set_contract_version(deps.storage, &String::from(CONTRACT_VERSION))?;
+
     Ok(Response::default())
 }
 
@@ -563,9 +545,12 @@ pub fn get_valid_time_period(deps: &Deps) -> StdResult<Duration> {
 mod test {
     use {
         super::*,
-        crate::governance::GovernanceModule::{
-            Executor,
-            Target,
+        crate::{
+            governance::GovernanceModule::{
+                Executor,
+                Target,
+            },
+            state::get_contract_version,
         },
         cosmwasm_std::{
             coins,
@@ -754,6 +739,75 @@ mod test {
         update_price_feeds(deps.as_mut(), env, info, &[msg])
     }
 
+    #[test]
+    fn test_instantiate() {
+        let mut deps = mock_dependencies();
+
+        let instantiate_msg = InstantiateMsg {
+            // this is an example wormhole contract address in order to create a valid instantiate message
+            wormhole_contract:          String::from("inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg"),
+            data_sources:               Vec::new(),
+            governance_source:          PythDataSource {
+                emitter:  Binary(vec![]),
+                chain_id: 0,
+            },
+            governance_source_index:    0,
+            governance_sequence_number: 0,
+            chain_id:                   0,
+            valid_time_period_secs:     0,
+            fee:                        Coin::new(0, ""),
+        };
+
+        let res = instantiate(
+            deps.as_mut(),
+            mock_env(),
+            MessageInfo {
+                sender: Addr::unchecked(""),
+                funds:  Vec::new(),
+            },
+            instantiate_msg,
+        );
+        assert!(res.is_ok());
+
+        // check config
+        let config_result = config(&mut deps.storage).load();
+        assert!(config_result.is_ok());
+
+        // check contract version
+        let contract_version = get_contract_version(&mut deps.storage);
+        assert_eq!(contract_version, Ok(String::from(CONTRACT_VERSION)));
+    }
+
+    #[test]
+    fn test_instantiate_invalid_wormhole_address() {
+        let mut deps = mock_dependencies();
+
+        let instantiate_msg = InstantiateMsg {
+            wormhole_contract:          String::from(""),
+            data_sources:               Vec::new(),
+            governance_source:          PythDataSource {
+                emitter:  Binary(vec![]),
+                chain_id: 0,
+            },
+            governance_source_index:    0,
+            governance_sequence_number: 0,
+            chain_id:                   0,
+            valid_time_period_secs:     0,
+            fee:                        Coin::new(0, ""),
+        };
+
+        let res = instantiate(
+            deps.as_mut(),
+            mock_env(),
+            MessageInfo {
+                sender: Addr::unchecked(""),
+                funds:  Vec::new(),
+            },
+            instantiate_msg,
+        );
+        assert!(res.is_err());
+    }
+
     #[test]
     fn test_process_batch_attestation_empty_array() {
         let (mut deps, env) = setup_test();

+ 6 - 34
target_chains/cosmwasm/contracts/pyth/src/state.rs

@@ -3,6 +3,7 @@ use {
         Addr,
         Binary,
         Coin,
+        StdResult,
         Storage,
     },
     cosmwasm_storage::{
@@ -27,9 +28,9 @@ use {
     },
 };
 
-pub static DEPRECATED_CONFIG_KEY: &[u8] = b"config";
 pub static CONFIG_KEY: &[u8] = b"config_v1";
 pub static PRICE_FEED_KEY: &[u8] = b"price_feed";
+pub static CONTRACT_VERSION_KEY: &[u8] = b"contract_version";
 
 /// A `PythDataSource` identifies a specific contract (given by its Wormhole `emitter`) on
 /// a specific blockchain (given by `chain_id`).
@@ -80,39 +81,10 @@ pub fn price_feed_read_bucket(storage: &dyn Storage) -> ReadonlyBucket<PriceFeed
     bucket_read(storage, PRICE_FEED_KEY)
 }
 
-
-// this code is only added to facilititate migration
-// once migrated this code can be removed
-#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
-pub struct DepreceatedConfigInfo {
-    pub owner:                      Addr,
-    pub wormhole_contract:          Addr,
-    pub data_sources:               HashSet<PythDataSource>,
-    pub governance_source:          PythDataSource,
-    // Index for preventing replay attacks on governance data source transfers.
-    // This index increases every time the governance data source is changed, which prevents old
-    // transfer request VAAs from being replayed.
-    pub governance_source_index:    u32,
-    // The wormhole sequence number for governance messages. This value is increased every time the
-    // a governance instruction is executed.
-    //
-    // This field differs from the one above in that it is generated by wormhole and applicable to all
-    // governance messages, whereas the one above is generated by Pyth and only applicable to governance
-    // source transfers.
-    pub governance_sequence_number: u64,
-    // Warning: This id needs to agree with the wormhole chain id.
-    // We should read this directly from wormhole, but their contract doesn't expose it.
-    pub chain_id:                   u16,
-    pub valid_time_period:          Duration,
-
-    // The fee to pay, denominated in fee_denom (typically, the chain's native token)
-    pub fee: Coin,
-}
-
-pub fn deprecated_config(storage: &mut dyn Storage) -> Singleton<DepreceatedConfigInfo> {
-    singleton(storage, DEPRECATED_CONFIG_KEY)
+pub fn set_contract_version(storage: &mut dyn Storage, contract_version: &String) -> StdResult<()> {
+    singleton(storage, CONTRACT_VERSION_KEY).save(contract_version)
 }
 
-pub fn deprecated_config_read(storage: &dyn Storage) -> ReadonlySingleton<DepreceatedConfigInfo> {
-    singleton_read(storage, DEPRECATED_CONFIG_KEY)
+pub fn get_contract_version(storage: &mut dyn Storage) -> StdResult<String> {
+    singleton_read(storage, CONTRACT_VERSION_KEY).load()
 }