[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
This commit is contained in:
Dev Kalra 2023-03-30 22:35:53 +05:30 committed by GitHub
parent 1af86140f1
commit 0b9f1f161d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 66 deletions

View File

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

View File

@ -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"

View File

@ -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": {

View File

@ -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,10 +545,13 @@ pub fn get_valid_time_period(deps: &Deps) -> StdResult<Duration> {
mod test {
use {
super::*,
crate::governance::GovernanceModule::{
crate::{
governance::GovernanceModule::{
Executor,
Target,
},
state::get_contract_version,
},
cosmwasm_std::{
coins,
from_binary,
@ -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();

View File

@ -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 set_contract_version(storage: &mut dyn Storage, contract_version: &String) -> StdResult<()> {
singleton(storage, CONTRACT_VERSION_KEY).save(contract_version)
}
pub fn deprecated_config(storage: &mut dyn Storage) -> Singleton<DepreceatedConfigInfo> {
singleton(storage, DEPRECATED_CONFIG_KEY)
}
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()
}