Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unifying instantiate2 implementation #212

Merged
merged 7 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ thiserror = "1.0.63"
[dev-dependencies]
hex = "0.4.3"
hex-literal = "0.4.1"
once_cell = "1.20.0"
once_cell = "1.19.0"
29 changes: 27 additions & 2 deletions src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use crate::error::{anyhow, bail, AnyError, AnyResult};
use cosmwasm_std::{
from_json, Binary, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env, MessageInfo,
QuerierWrapper, Reply, Response, SubMsg,
from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env,
MessageInfo, QuerierWrapper, Reply, Response, SubMsg,
};
use serde::de::DeserializeOwned;
use std::fmt::{Debug, Display};
Expand Down Expand Up @@ -33,6 +33,11 @@

/// Evaluates contract's `migrate` entry-point.
fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Response<C>>;

/// Returns the provided checksum of the contract's Wasm blob.
fn checksum(&self) -> Option<Checksum> {
None

Check warning on line 39 in src/contracts.rs

View check run for this annotation

Codecov / codecov/patch

src/contracts.rs#L38-L39

Added lines #L38 - L39 were not covered by tests
}
}

#[rustfmt::skip]
Expand Down Expand Up @@ -156,6 +161,7 @@
sudo_fn: Option<PermissionedClosure<T4, C, E4, Q>>,
reply_fn: Option<ReplyClosure<C, E5, Q>>,
migrate_fn: Option<PermissionedClosure<T6, C, E6, Q>>,
checksum: Option<Checksum>,
}

impl<T1, T2, T3, E1, E2, E3, C, Q> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q>
Expand All @@ -182,6 +188,7 @@
sudo_fn: None,
reply_fn: None,
migrate_fn: None,
checksum: None,
}
}

Expand All @@ -199,6 +206,7 @@
sudo_fn: None,
reply_fn: None,
migrate_fn: None,
checksum: None,
}
}
}
Expand Down Expand Up @@ -237,6 +245,7 @@
sudo_fn: Some(Box::new(sudo_fn)),
reply_fn: self.reply_fn,
migrate_fn: self.migrate_fn,
checksum: None,
}
}

Expand All @@ -256,6 +265,7 @@
sudo_fn: Some(customize_permissioned_fn(sudo_fn)),
reply_fn: self.reply_fn,
migrate_fn: self.migrate_fn,
checksum: None,
}
}

Expand All @@ -274,6 +284,7 @@
sudo_fn: self.sudo_fn,
reply_fn: Some(Box::new(reply_fn)),
migrate_fn: self.migrate_fn,
checksum: None,
}
}

Expand All @@ -292,6 +303,7 @@
sudo_fn: self.sudo_fn,
reply_fn: Some(customize_permissioned_fn(reply_fn)),
migrate_fn: self.migrate_fn,
checksum: None,
}
}

Expand All @@ -311,6 +323,7 @@
sudo_fn: self.sudo_fn,
reply_fn: self.reply_fn,
migrate_fn: Some(Box::new(migrate_fn)),
checksum: None,
}
}

Expand All @@ -330,8 +343,15 @@
sudo_fn: self.sudo_fn,
reply_fn: self.reply_fn,
migrate_fn: Some(customize_permissioned_fn(migrate_fn)),
checksum: None,
}
}

/// Populates [ContractWrapper] with the provided checksum of the contract's Wasm blob.
pub fn with_checksum(mut self, checksum: Checksum) -> Self {
self.checksum = Some(checksum);
self
}
}

fn customize_contract_fn<T, C, E, Q>(
Expand Down Expand Up @@ -534,4 +554,9 @@
None => bail!("migrate is not implemented for contract"),
}
}

/// Returns the provided checksum of the contract's Wasm blob.
fn checksum(&self) -> Option<Checksum> {
self.checksum
}
}
170 changes: 85 additions & 85 deletions src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,90 +337,6 @@
}
}

impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC> {
/// Returns a handler to code of the contract with specified code id.
pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract<ExecC, QueryC>> {
let code_data = self.code_data(code_id)?;
Ok(self.code_base[code_data.source_id].borrow())
}

/// Returns code data of the contract with specified code id.
fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> {
if code_id < 1 {
bail!(Error::invalid_code_id());
}
Ok(self
.code_data
.get(&code_id)
.ok_or_else(|| Error::unregistered_code_id(code_id))?)
}

/// Validates all attributes.
///
/// In `wasmd`, before version v0.45.0 empty attribute values were not allowed.
/// Since `wasmd` v0.45.0 empty attribute values are allowed,
/// so the value is not validated anymore.
fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> {
for attr in attributes {
let key = attr.key.trim();
let val = attr.value.trim();
if key.is_empty() {
bail!(Error::empty_attribute_key(val));
}
if key.starts_with('_') {
bail!(Error::reserved_attribute_key(key));
}
}
Ok(())
}

fn verify_response<T>(response: Response<T>) -> AnyResult<Response<T>>
where
T: CustomMsg,
{
Self::verify_attributes(&response.attributes)?;

for event in &response.events {
Self::verify_attributes(&event.attributes)?;
let ty = event.ty.trim();
if ty.len() < 2 {
bail!(Error::event_type_too_short(ty));
}
}

Ok(response)
}

fn save_code(
&mut self,
code_id: u64,
creator: Addr,
code: Box<dyn Contract<ExecC, QueryC>>,
) -> u64 {
// prepare the next identifier for the contract 'source' code
let source_id = self.code_base.len();
// calculate the checksum of the contract 'source' code based on code_id
let checksum = self.checksum_generator.checksum(&creator, code_id);
// store the 'source' code of the contract
self.code_base.push(code);
// store the additional code attributes like creator address and checksum
self.code_data.insert(
code_id,
CodeData {
creator,
checksum,
source_id,
},
);
code_id
}

/// Returns the next code identifier.
fn next_code_id(&self) -> Option<u64> {
self.code_data.keys().last().unwrap_or(&0u64).checked_add(1)
}
}

impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC>
where
ExecC: CustomMsg + DeserializeOwned + 'static,
Expand Down Expand Up @@ -513,7 +429,91 @@
self
}

/// Executes contract's `query` entry-point.
/// Returns a handler to code of the contract with specified code id.
pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract<ExecC, QueryC>> {
let code_data = self.code_data(code_id)?;
Ok(self.code_base[code_data.source_id].borrow())

Check warning on line 435 in src/wasm.rs

View check run for this annotation

Codecov / codecov/patch

src/wasm.rs#L435

Added line #L435 was not covered by tests
}

/// Returns code data of the contract with specified code id.
fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> {
if code_id < 1 {
bail!(Error::invalid_code_id());
}
Ok(self
.code_data
.get(&code_id)
.ok_or_else(|| Error::unregistered_code_id(code_id))?)
}

/// Validates all attributes.
///
/// In `wasmd`, before version v0.45.0 empty attribute values were not allowed.
/// Since `wasmd` v0.45.0 empty attribute values are allowed,
/// so the value is not validated anymore.
fn verify_attributes(attributes: &[Attribute]) -> AnyResult<()> {
for attr in attributes {
let key = attr.key.trim();
let val = attr.value.trim();
if key.is_empty() {

Check warning on line 458 in src/wasm.rs

View check run for this annotation

Codecov / codecov/patch

src/wasm.rs#L456-L458

Added lines #L456 - L458 were not covered by tests
bail!(Error::empty_attribute_key(val));
}
if key.starts_with('_') {
bail!(Error::reserved_attribute_key(key));

Check warning on line 462 in src/wasm.rs

View check run for this annotation

Codecov / codecov/patch

src/wasm.rs#L462

Added line #L462 was not covered by tests
}
}
Ok(())
}

fn verify_response<T>(response: Response<T>) -> AnyResult<Response<T>>
where
T: CustomMsg,
{
Self::verify_attributes(&response.attributes)?;

for event in &response.events {
Self::verify_attributes(&event.attributes)?;
let ty = event.ty.trim();
if ty.len() < 2 {
bail!(Error::event_type_too_short(ty));
}
}

Ok(response)
}

fn save_code(
&mut self,
code_id: u64,
creator: Addr,
code: Box<dyn Contract<ExecC, QueryC>>,
) -> u64 {
// prepare the next identifier for the contract's code
let source_id = self.code_base.len();
// prepare the contract's Wasm blob checksum
let checksum = code
.checksum()
.unwrap_or(self.checksum_generator.checksum(&creator, code_id));
// store the 'source' code of the contract
self.code_base.push(code);
// store the additional code attributes like creator address and checksum
self.code_data.insert(
code_id,
CodeData {
creator,
checksum,
source_id,
},
);
code_id
}

/// Returns the next contract's code identifier.
fn next_code_id(&self) -> Option<u64> {
self.code_data.keys().last().unwrap_or(&0u64).checked_add(1)
}

/// Executes the contract's `query` entry-point.
pub fn query_smart(
&self,
address: Addr,
Expand Down
9 changes: 9 additions & 0 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,14 @@ mod test_contracts {
pub fn contract() -> Box<dyn Contract<Empty>> {
Box::new(ContractWrapper::new_with_empty(execute, instantiate, query))
}

#[cfg(feature = "cosmwasm_1_2")]
pub fn contract_with_checksum() -> Box<dyn Contract<Empty>> {
Box::new(
ContractWrapper::new_with_empty(execute, instantiate, query).with_checksum(
cosmwasm_std::Checksum::generate(&[1, 2, 3, 4, 5, 6, 7, 8, 9]),
),
)
}
}
}
2 changes: 0 additions & 2 deletions tests/test_app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
mod test_block_info;
mod test_initialize_app;
#[cfg(feature = "cosmwasm_1_2")]
mod test_instantiate2;
mod test_store_code;
#[cfg(feature = "cosmwasm_1_2")]
mod test_store_code_with_creator;
mod test_store_code_with_id;
Loading