Skip to content

Commit e0c3c90

Browse files
authored
Merge pull request #295 from CosmWasm/extensible-cosmos-msg
Extensible Native variant for CosmosMsg
2 parents 1434dba + 4563b16 commit e0c3c90

File tree

23 files changed

+650
-217
lines changed

23 files changed

+650
-217
lines changed

CHANGELOG.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@
4040
- `Env.message.sent_funds` is a `Vec<Coin>` not `Option<Vec<Coin>>`. We will
4141
normalize the go response in `go-cosmwasm` before sending it to the contract.
4242
- `Env.block.{height,time}` are now `u64` rather than `i64`.
43-
- Reorganize `CosmosMsg` enum types. They are now split by modules:
44-
`CosmosMsg::Bank(BankMsg)`, `CosmosMsg::Native { msg }`,
45-
`CosmosMsg::Wasm(WasmMsg)`
4643

4744
**cosmwasm-schema**
4845

@@ -93,6 +90,13 @@
9390
- Rename `Error` to `StdError`.
9491
- `ExternalStorage.get` now returns an empty vector if a storage entry exists
9592
but has an empty value. Before, this was normalized to `None`.
93+
- Reorganize `CosmosMsg` enum types. They are now split by modules:
94+
`CosmosMsg::Bank(BankMsg)`, `CosmosMsg::Custom(T)`,
95+
`CosmosMsg::Wasm(WasmMsg)`
96+
- CosmosMsg is now generic over the content of `Custom` variant. This allows
97+
blockchains to support custom native calls in their Cosmos-SDK apps and
98+
developers to make use of them in CosmWasm apps without forking the
99+
`cosmwasm-vm` and `go-cosmwasm` runtime.
96100

97101
**cosmwasm-vm**
98102

MIGRATING.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ Integration Tests:
109109
`match err { ContractResult::Err(msg) => assert_eq!(msg, "Unauthorized"), ... }`
110110
- After: `match err { Err(ApiError::Unauthorized{ ..}) => {}, ... }`
111111
- Remove all imports / use of `ContractResult`
112+
- You must specify `CosmosMsg::Native` type when calling
113+
`cosmwasm_vm::testing::{handle, init}`. You will want to
114+
`use cosmwasm_vm::testing::{HandleResult, InitResult}` or
115+
`use cosmwasm_std::{HandleResponse, InitResponse}`. If you don't use custom
116+
native types, simply update calls as follows:
117+
- `let res = init(...)` => `let res: InitResult = init(...)`
118+
- `let res = init(...).unwrap()` =>
119+
`let res: InitResponse = init(...).unwrap()`
120+
- `let res = handle(...)` => `let res: HandleResult = handle(...)`
121+
- `let res = handle(...).unwrap()` =>
122+
`let res: HandleResponse = handle(...).unwrap()`
112123

113124
### Update schema code
114125

contracts/hackatom/src/contract.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use snafu::OptionExt;
44

55
use cosmwasm_std::{
66
contract_err, from_slice, log, to_binary, to_vec, unauthorized, Api, BankMsg, Binary,
7-
CanonicalAddr, CosmosMsg, Env, Extern, HandleResponse, HumanAddr, InitResponse, NotFound,
8-
Querier, QueryResponse, StdResult, Storage,
7+
CanonicalAddr, Env, Extern, HandleResponse, HumanAddr, InitResponse, NotFound, Querier,
8+
QueryResponse, StdResult, Storage,
99
};
1010

1111
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -108,11 +108,12 @@ fn do_release<S: Storage, A: Api, Q: Querier>(
108108
log("action", "release"),
109109
log("destination", to_addr.as_str()),
110110
],
111-
messages: vec![CosmosMsg::Bank(BankMsg::Send {
111+
messages: vec![BankMsg::Send {
112112
from_address: from_addr,
113113
to_address: to_addr,
114114
amount: balance.amount,
115-
})],
115+
}
116+
.into()],
116117
data: None,
117118
};
118119
Ok(res)
@@ -343,11 +344,12 @@ mod tests {
343344
let msg = handle_res.messages.get(0).expect("no message");
344345
assert_eq!(
345346
msg,
346-
&CosmosMsg::Bank(BankMsg::Send {
347+
&BankMsg::Send {
347348
from_address: HumanAddr("cosmos2contract".to_string()),
348349
to_address: beneficiary,
349350
amount: coins(1015, "earth"),
350-
}),
351+
}
352+
.into(),
351353
);
352354
assert_eq!(
353355
handle_res.log,

contracts/hackatom/tests/integration.rs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@
3030
3131
use cosmwasm_std::testing::mock_env;
3232
use cosmwasm_std::{
33-
coins, from_binary, log, AllBalanceResponse, Api, ApiError, BankMsg, CosmosMsg, HumanAddr,
34-
ReadonlyStorage,
33+
coins, from_binary, log, AllBalanceResponse, Api, ApiError, BankMsg, HandleResponse, HumanAddr,
34+
InitResponse, NoMsg, ReadonlyStorage,
3535
};
3636
use cosmwasm_vm::from_slice;
3737
use cosmwasm_vm::testing::{
38-
handle, init, mock_instance, mock_instance_with_balances, query, test_io,
38+
handle, init, mock_instance, mock_instance_with_balances, query, test_io, HandleResult,
39+
InitResult,
3940
};
4041

4142
use hackatom::contract::{HandleMsg, InitMsg, QueryMsg, State, CONFIG_KEY};
@@ -59,7 +60,7 @@ fn proper_initialization() {
5960
beneficiary,
6061
};
6162
let env = mock_env(&deps.api, "creator", &coins(1000, "earth"));
62-
let res = init(&mut deps, env, msg).unwrap();
63+
let res: InitResponse = init(&mut deps, env, msg).unwrap();
6364
assert_eq!(0, res.messages.len());
6465

6566
// it worked, let's check the state
@@ -87,7 +88,7 @@ fn init_and_query() {
8788
beneficiary,
8889
};
8990
let env = mock_env(&deps.api, creator.as_str(), &coins(1000, "earth"));
90-
let res = init(&mut deps, env, msg).unwrap();
91+
let res: InitResponse = init(&mut deps, env, msg).unwrap();
9192
assert_eq!(0, res.messages.len());
9293

9394
// now let's query
@@ -128,7 +129,7 @@ fn fails_on_bad_init() {
128129
let mut deps = mock_instance(WASM, &[]);
129130
let env = mock_env(&deps.api, "creator", &coins(1000, "earth"));
130131
// bad init returns parse error (pass wrong type - this connection is not enforced)
131-
let res = init(&mut deps, env, HandleMsg::Release {});
132+
let res: InitResult = init(&mut deps, env, HandleMsg::Release {});
132133
match res.unwrap_err() {
133134
ApiError::ParseErr { .. } => {}
134135
_ => panic!("Expected parse error"),
@@ -148,21 +149,22 @@ fn proper_handle() {
148149
beneficiary: beneficiary.clone(),
149150
};
150151
let init_env = mock_env(&deps.api, "creator", &coins(1000, "earth"));
151-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
152+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
152153
assert_eq!(0, init_res.messages.len());
153154

154155
// beneficiary can release it
155156
let handle_env = mock_env(&deps.api, verifier.as_str(), &coins(15, "earth"));
156-
let handle_res = handle(&mut deps, handle_env, HandleMsg::Release {}).unwrap();
157+
let handle_res: HandleResponse = handle(&mut deps, handle_env, HandleMsg::Release {}).unwrap();
157158
assert_eq!(1, handle_res.messages.len());
158159
let msg = handle_res.messages.get(0).expect("no message");
159160
assert_eq!(
160161
msg,
161-
&CosmosMsg::Bank(BankMsg::Send {
162+
&BankMsg::Send {
162163
from_address: HumanAddr("cosmos2contract".to_string()),
163164
to_address: beneficiary,
164165
amount: coins(1015, "earth"),
165-
}),
166+
}
167+
.into(),
166168
);
167169
assert_eq!(
168170
handle_res.log,
@@ -184,12 +186,12 @@ fn failed_handle() {
184186
beneficiary: beneficiary.clone(),
185187
};
186188
let init_env = mock_env(&deps.api, creator.as_str(), &coins(1000, "earth"));
187-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
189+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
188190
assert_eq!(0, init_res.messages.len());
189191

190192
// beneficiary cannot release it
191193
let handle_env = mock_env(&deps.api, beneficiary.as_str(), &[]);
192-
let handle_res = handle(&mut deps, handle_env, HandleMsg::Release {});
194+
let handle_res: HandleResult = handle(&mut deps, handle_env, HandleMsg::Release {});
193195
match handle_res.unwrap_err() {
194196
ApiError::Unauthorized {} => {}
195197
_ => panic!("Expect unauthorized error"),
@@ -247,13 +249,13 @@ mod singlepass_tests {
247249

248250
let (init_msg, creator) = make_init_msg();
249251
let init_env = mock_env(&deps.api, creator.as_str(), &[]);
250-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
252+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
251253
assert_eq!(0, init_res.messages.len());
252254

253255
let handle_env = mock_env(&deps.api, creator.as_str(), &[]);
254256
// panic inside contract should not panic out here
255257
// Note: we need to use the production-call, not the testing call (which unwraps any vm error)
256-
let handle_res = call_handle(
258+
let handle_res = call_handle::<_, _, _, NoMsg>(
257259
&mut deps,
258260
&handle_env,
259261
&to_vec(&HandleMsg::Panic {}).unwrap(),
@@ -267,12 +269,12 @@ mod singlepass_tests {
267269

268270
let (init_msg, creator) = make_init_msg();
269271
let init_env = mock_env(&deps.api, creator.as_str(), &[]);
270-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
272+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
271273
assert_eq!(0, init_res.messages.len());
272274

273275
let handle_env = mock_env(&deps.api, creator.as_str(), &[]);
274276
// Note: we need to use the production-call, not the testing call (which unwraps any vm error)
275-
let handle_res = call_handle(
277+
let handle_res = call_handle::<_, _, _, NoMsg>(
276278
&mut deps,
277279
&handle_env,
278280
&to_vec(&HandleMsg::CpuLoop {}).unwrap(),
@@ -287,12 +289,12 @@ mod singlepass_tests {
287289

288290
let (init_msg, creator) = make_init_msg();
289291
let init_env = mock_env(&deps.api, creator.as_str(), &[]);
290-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
292+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
291293
assert_eq!(0, init_res.messages.len());
292294

293295
let handle_env = mock_env(&deps.api, creator.as_str(), &[]);
294296
// Note: we need to use the production-call, not the testing call (which unwraps any vm error)
295-
let handle_res = call_handle(
297+
let handle_res = call_handle::<_, _, _, NoMsg>(
296298
&mut deps,
297299
&handle_env,
298300
&to_vec(&HandleMsg::StorageLoop {}).unwrap(),
@@ -307,12 +309,12 @@ mod singlepass_tests {
307309

308310
let (init_msg, creator) = make_init_msg();
309311
let init_env = mock_env(&deps.api, creator.as_str(), &[]);
310-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
312+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
311313
assert_eq!(0, init_res.messages.len());
312314

313315
let handle_env = mock_env(&deps.api, creator.as_str(), &[]);
314316
// Note: we need to use the production-call, not the testing call (which unwraps any vm error)
315-
let handle_res = call_handle(
317+
let handle_res = call_handle::<_, _, _, NoMsg>(
316318
&mut deps,
317319
&handle_env,
318320
&to_vec(&HandleMsg::MemoryLoop {}).unwrap(),
@@ -330,13 +332,13 @@ mod singlepass_tests {
330332

331333
let (init_msg, creator) = make_init_msg();
332334
let init_env = mock_env(&deps.api, creator.as_str(), &[]);
333-
let init_res = init(&mut deps, init_env, init_msg).unwrap();
335+
let init_res: InitResponse = init(&mut deps, init_env, init_msg).unwrap();
334336
assert_eq!(0, init_res.messages.len());
335337

336338
let handle_env = mock_env(&deps.api, creator.as_str(), &[]);
337339
let gas_before = deps.get_gas();
338340
// Note: we need to use the production-call, not the testing call (which unwraps any vm error)
339-
let handle_res = call_handle(
341+
let handle_res = call_handle::<_, _, _, NoMsg>(
340342
&mut deps,
341343
&handle_env,
342344
&to_vec(&HandleMsg::AllocateLargeMemory {}).unwrap(),
@@ -349,8 +351,8 @@ mod singlepass_tests {
349351
// Gas consumtion is relatively small
350352
// Note: the exact gas usage depends on the Rust version used to compile WASM,
351353
// which we only fix when using cosmwasm-opt, not integration tests.
352-
assert!(gas_used > 28000);
353-
assert!(gas_used < 32000);
354+
assert!(gas_used > 26000, "{}", gas_used);
355+
assert!(gas_used < 30000, "{}", gas_used);
354356

355357
// Used between 100 and 102 MiB of memory
356358
assert!(deps.get_memory_size() > 100 * 1024 * 1024);

contracts/queue/tests/integration.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
//! }
3030
3131
use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier, MockStorage};
32-
use cosmwasm_std::{from_binary, from_slice, Env, HumanAddr};
32+
use cosmwasm_std::{from_binary, from_slice, Env, HandleResponse, HumanAddr, InitResponse};
3333
use cosmwasm_vm::testing::{handle, init, mock_instance, query};
3434
use cosmwasm_vm::Instance;
3535

@@ -43,7 +43,7 @@ fn create_contract() -> (Instance<MockStorage, MockApi, MockQuerier>, Env) {
4343
let mut deps = mock_instance(WASM, &[]);
4444
let creator = HumanAddr(String::from("creator"));
4545
let env = mock_env(&deps.api, creator.as_str(), &[]);
46-
let res = init(&mut deps, env.clone(), InitMsg {}).unwrap();
46+
let res: InitResponse = init(&mut deps, env.clone(), InitMsg {}).unwrap();
4747
assert_eq!(0, res.messages.len());
4848
(deps, env)
4949
}
@@ -70,27 +70,33 @@ fn init_and_query() {
7070
#[test]
7171
fn push_and_query() {
7272
let (mut deps, env) = create_contract();
73-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
73+
let _: HandleResponse =
74+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
7475
assert_eq!(get_count(&mut deps), 1);
7576
assert_eq!(get_sum(&mut deps), 25);
7677
}
7778

7879
#[test]
7980
fn multiple_push() {
8081
let (mut deps, env) = create_contract();
81-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
82-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 35 }).unwrap();
83-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 45 }).unwrap();
82+
let _: HandleResponse =
83+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
84+
let _: HandleResponse =
85+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 35 }).unwrap();
86+
let _: HandleResponse =
87+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 45 }).unwrap();
8488
assert_eq!(get_count(&mut deps), 3);
8589
assert_eq!(get_sum(&mut deps), 105);
8690
}
8791

8892
#[test]
8993
fn push_and_pop() {
9094
let (mut deps, env) = create_contract();
91-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
92-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 17 }).unwrap();
93-
let res = handle(&mut deps, env.clone(), HandleMsg::Dequeue {}).unwrap();
95+
let _: HandleResponse =
96+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 25 }).unwrap();
97+
let _: HandleResponse =
98+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 17 }).unwrap();
99+
let res: HandleResponse = handle(&mut deps, env.clone(), HandleMsg::Dequeue {}).unwrap();
94100
// ensure we popped properly
95101
assert!(res.data.is_some());
96102
let data = res.data.unwrap();
@@ -104,10 +110,14 @@ fn push_and_pop() {
104110
#[test]
105111
fn push_and_reduce() {
106112
let (mut deps, env) = create_contract();
107-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 40 }).unwrap();
108-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 15 }).unwrap();
109-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 85 }).unwrap();
110-
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: -10 }).unwrap();
113+
let _: HandleResponse =
114+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 40 }).unwrap();
115+
let _: HandleResponse =
116+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 15 }).unwrap();
117+
let _: HandleResponse =
118+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: 85 }).unwrap();
119+
let _: HandleResponse =
120+
handle(&mut deps, env.clone(), HandleMsg::Enqueue { value: -10 }).unwrap();
111121
assert_eq!(get_count(&mut deps), 4);
112122
assert_eq!(get_sum(&mut deps), 130);
113123
let data = query(&mut deps, QueryMsg::Reducer {}).unwrap();

contracts/reflect/examples/schema.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use std::env::current_dir;
22
use std::fs::create_dir_all;
33

44
use cosmwasm_schema::{export_schema, remove_schemas, schema_for};
5+
use cosmwasm_std::HandleResponse;
56

6-
use reflect::msg::{HandleMsg, InitMsg, OwnerResponse, QueryMsg};
7+
use reflect::msg::{CustomMsg, HandleMsg, InitMsg, OwnerResponse, QueryMsg};
78
use reflect::state::State;
89

910
fn main() {
@@ -12,8 +13,10 @@ fn main() {
1213
create_dir_all(&out_dir).unwrap();
1314
remove_schemas(&out_dir).unwrap();
1415

16+
export_schema(&schema_for!(CustomMsg), &out_dir);
1517
export_schema(&schema_for!(InitMsg), &out_dir);
1618
export_schema(&schema_for!(HandleMsg), &out_dir);
19+
export_schema(&schema_for!(HandleResponse<CustomMsg>), &out_dir);
1720
export_schema(&schema_for!(QueryMsg), &out_dir);
1821
export_schema(&schema_for!(State), &out_dir);
1922
export_schema(&schema_for!(OwnerResponse), &out_dir);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "CustomMsg",
4+
"description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract",
5+
"anyOf": [
6+
{
7+
"type": "object",
8+
"required": [
9+
"debug"
10+
],
11+
"properties": {
12+
"debug": {
13+
"type": "string"
14+
}
15+
}
16+
},
17+
{
18+
"type": "object",
19+
"required": [
20+
"raw"
21+
],
22+
"properties": {
23+
"raw": {
24+
"$ref": "#/definitions/Binary"
25+
}
26+
}
27+
}
28+
],
29+
"definitions": {
30+
"Binary": {
31+
"description": "Binary is a wrapper around Vec<u8> to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec<u8>",
32+
"type": "string"
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)