Skip to content

Commit 0b9f1f1

Browse files
author
Dev Kalra
authored
[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
1 parent 1af8614 commit 0b9f1f1

File tree

5 files changed

+93
-66
lines changed

5 files changed

+93
-66
lines changed

target_chains/cosmwasm/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

target_chains/cosmwasm/contracts/pyth/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-cosmwasm"
3-
version = "1.0.0"
3+
version = "1.1.0"
44
authors = ["Wormhole Contributors <[email protected]>"]
55
edition = "2018"
66
description = "Pyth price receiver"

target_chains/cosmwasm/contracts/pyth/schema/pyth-cosmwasm.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"contract_name": "pyth-cosmwasm",
3-
"contract_version": "0.1.0",
3+
"contract_version": "1.1.0",
44
"idl_version": "1.0.0",
55
"instantiate": {
66
"$schema": "http://json-schema.org/draft-07/schema#",
@@ -72,6 +72,7 @@
7272
}
7373
},
7474
"PythDataSource": {
75+
"description": "A `PythDataSource` identifies a specific contract (given by its Wormhole `emitter`) on a specific blockchain (given by `chain_id`).",
7576
"type": "object",
7677
"required": ["chain_id", "emitter"],
7778
"properties": {

target_chains/cosmwasm/contracts/pyth/src/contract.rs

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ use {
2626
state::{
2727
config,
2828
config_read,
29-
deprecated_config,
30-
deprecated_config_read,
3129
price_feed_bucket,
3230
price_feed_read_bucket,
31+
set_contract_version,
3332
ConfigInfo,
3433
PythDataSource,
3534
},
@@ -51,7 +50,6 @@ use {
5150
OverflowOperation,
5251
QueryRequest,
5352
Response,
54-
StdError,
5553
StdResult,
5654
WasmMsg,
5755
WasmQuery,
@@ -82,6 +80,8 @@ use {
8280
},
8381
};
8482

83+
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
84+
8585
/// Migration code that runs once when the contract is upgraded. On upgrade, the migrate
8686
/// function in the *new* code version is run, which allows the new code to update the on-chain
8787
/// state before any of its other functions are invoked.
@@ -94,29 +94,9 @@ use {
9494
/// `Ok(Response::default())`
9595
#[cfg_attr(not(feature = "library"), entry_point)]
9696
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
97-
let depreceated_cfg_result = deprecated_config_read(deps.storage).load();
98-
match depreceated_cfg_result {
99-
Ok(depreceated_cfg) => {
100-
let cfg = ConfigInfo {
101-
wormhole_contract: depreceated_cfg.wormhole_contract,
102-
data_sources: depreceated_cfg.data_sources,
103-
governance_source: depreceated_cfg.governance_source,
104-
governance_source_index: depreceated_cfg.governance_source_index,
105-
governance_sequence_number: depreceated_cfg.governance_sequence_number,
106-
chain_id: depreceated_cfg.chain_id,
107-
valid_time_period: depreceated_cfg.valid_time_period,
108-
fee: depreceated_cfg.fee,
109-
};
110-
111-
config(deps.storage).save(&cfg)?;
112-
deprecated_config(deps.storage).remove();
113-
114-
Ok(Response::default())
115-
}
116-
Err(_) => Err(StdError::GenericErr {
117-
msg: String::from("Error reading config"),
118-
}),
119-
}
97+
// a new contract version should be set everytime a contract is migrated
98+
set_contract_version(deps.storage, &String::from(CONTRACT_VERSION))?;
99+
Ok(Response::default().add_attribute("Contract Version", CONTRACT_VERSION))
120100
}
121101

122102
#[cfg_attr(not(feature = "library"), entry_point)]
@@ -139,6 +119,8 @@ pub fn instantiate(
139119
};
140120
config(deps.storage).save(&state)?;
141121

122+
set_contract_version(deps.storage, &String::from(CONTRACT_VERSION))?;
123+
142124
Ok(Response::default())
143125
}
144126

@@ -563,9 +545,12 @@ pub fn get_valid_time_period(deps: &Deps) -> StdResult<Duration> {
563545
mod test {
564546
use {
565547
super::*,
566-
crate::governance::GovernanceModule::{
567-
Executor,
568-
Target,
548+
crate::{
549+
governance::GovernanceModule::{
550+
Executor,
551+
Target,
552+
},
553+
state::get_contract_version,
569554
},
570555
cosmwasm_std::{
571556
coins,
@@ -754,6 +739,75 @@ mod test {
754739
update_price_feeds(deps.as_mut(), env, info, &[msg])
755740
}
756741

742+
#[test]
743+
fn test_instantiate() {
744+
let mut deps = mock_dependencies();
745+
746+
let instantiate_msg = InstantiateMsg {
747+
// this is an example wormhole contract address in order to create a valid instantiate message
748+
wormhole_contract: String::from("inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg"),
749+
data_sources: Vec::new(),
750+
governance_source: PythDataSource {
751+
emitter: Binary(vec![]),
752+
chain_id: 0,
753+
},
754+
governance_source_index: 0,
755+
governance_sequence_number: 0,
756+
chain_id: 0,
757+
valid_time_period_secs: 0,
758+
fee: Coin::new(0, ""),
759+
};
760+
761+
let res = instantiate(
762+
deps.as_mut(),
763+
mock_env(),
764+
MessageInfo {
765+
sender: Addr::unchecked(""),
766+
funds: Vec::new(),
767+
},
768+
instantiate_msg,
769+
);
770+
assert!(res.is_ok());
771+
772+
// check config
773+
let config_result = config(&mut deps.storage).load();
774+
assert!(config_result.is_ok());
775+
776+
// check contract version
777+
let contract_version = get_contract_version(&mut deps.storage);
778+
assert_eq!(contract_version, Ok(String::from(CONTRACT_VERSION)));
779+
}
780+
781+
#[test]
782+
fn test_instantiate_invalid_wormhole_address() {
783+
let mut deps = mock_dependencies();
784+
785+
let instantiate_msg = InstantiateMsg {
786+
wormhole_contract: String::from(""),
787+
data_sources: Vec::new(),
788+
governance_source: PythDataSource {
789+
emitter: Binary(vec![]),
790+
chain_id: 0,
791+
},
792+
governance_source_index: 0,
793+
governance_sequence_number: 0,
794+
chain_id: 0,
795+
valid_time_period_secs: 0,
796+
fee: Coin::new(0, ""),
797+
};
798+
799+
let res = instantiate(
800+
deps.as_mut(),
801+
mock_env(),
802+
MessageInfo {
803+
sender: Addr::unchecked(""),
804+
funds: Vec::new(),
805+
},
806+
instantiate_msg,
807+
);
808+
assert!(res.is_err());
809+
}
810+
757811
#[test]
758812
fn test_process_batch_attestation_empty_array() {
759813
let (mut deps, env) = setup_test();

target_chains/cosmwasm/contracts/pyth/src/state.rs

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use {
33
Addr,
44
Binary,
55
Coin,
6+
StdResult,
67
Storage,
78
},
89
cosmwasm_storage::{
@@ -27,9 +28,9 @@ use {
2728
},
2829
};
2930

30-
pub static DEPRECATED_CONFIG_KEY: &[u8] = b"config";
3131
pub static CONFIG_KEY: &[u8] = b"config_v1";
3232
pub static PRICE_FEED_KEY: &[u8] = b"price_feed";
33+
pub static CONTRACT_VERSION_KEY: &[u8] = b"contract_version";
3334

3435
/// A `PythDataSource` identifies a specific contract (given by its Wormhole `emitter`) on
3536
/// a specific blockchain (given by `chain_id`).
@@ -80,39 +81,10 @@ pub fn price_feed_read_bucket(storage: &dyn Storage) -> ReadonlyBucket<PriceFeed
8081
bucket_read(storage, PRICE_FEED_KEY)
8182
}
8283

83-
84-
// this code is only added to facilititate migration
85-
// once migrated this code can be removed
86-
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
87-
pub struct DepreceatedConfigInfo {
88-
pub owner: Addr,
89-
pub wormhole_contract: Addr,
90-
pub data_sources: HashSet<PythDataSource>,
91-
pub governance_source: PythDataSource,
92-
// Index for preventing replay attacks on governance data source transfers.
93-
// This index increases every time the governance data source is changed, which prevents old
94-
// transfer request VAAs from being replayed.
95-
pub governance_source_index: u32,
96-
// The wormhole sequence number for governance messages. This value is increased every time the
97-
// a governance instruction is executed.
98-
//
99-
// This field differs from the one above in that it is generated by wormhole and applicable to all
100-
// governance messages, whereas the one above is generated by Pyth and only applicable to governance
101-
// source transfers.
102-
pub governance_sequence_number: u64,
103-
// Warning: This id needs to agree with the wormhole chain id.
104-
// We should read this directly from wormhole, but their contract doesn't expose it.
105-
pub chain_id: u16,
106-
pub valid_time_period: Duration,
107-
108-
// The fee to pay, denominated in fee_denom (typically, the chain's native token)
109-
pub fee: Coin,
110-
}
111-
112-
pub fn deprecated_config(storage: &mut dyn Storage) -> Singleton<DepreceatedConfigInfo> {
113-
singleton(storage, DEPRECATED_CONFIG_KEY)
84+
pub fn set_contract_version(storage: &mut dyn Storage, contract_version: &String) -> StdResult<()> {
85+
singleton(storage, CONTRACT_VERSION_KEY).save(contract_version)
11486
}
11587

116-
pub fn deprecated_config_read(storage: &dyn Storage) -> ReadonlySingleton<DepreceatedConfigInfo> {
117-
singleton_read(storage, DEPRECATED_CONFIG_KEY)
88+
pub fn get_contract_version(storage: &mut dyn Storage) -> StdResult<String> {
89+
singleton_read(storage, CONTRACT_VERSION_KEY).load()
11890
}

0 commit comments

Comments
 (0)