@@ -266,8 +266,8 @@ pub fn ibc_packet_receive(
266266```
267267
268268This is a very special entry point as it has a unique workflow. (Please see the
269- [ Acknowledgement Processing section] ( #Acknowledgement-Processing ) below to
270- understand it fully).
269+ [ Acknowledging Errors section] ( #Acknowledging-Errors ) below to understand it
270+ fully).
271271
272272Also note the different return response here (` IbcReceiveResponse ` rather than
273273` IbcBasicResponse ` ). This is because it has an extra field
@@ -277,15 +277,23 @@ by the sending chain.
277277
278278The
279279[ ` IbcPacket ` structure] ( https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta4/packages/std/src/ibc.rs#L129-L146 )
280- contains all information needed to process the receipt. You can generally ignore
281- timeout (this entry point is only called if it hasn't yet timed out) and
282- sequence (which is used by the IBC framework to avoid duplicates). I generally
283- use ` dest.channel_id ` like ` info.sender ` to authenticate the packet, and parse
284- ` data ` into a ` PacketMsg ` structure, using the same encoding rules as we
285- discussed in the last section.
286-
287- After that you can process ` PacketMsg ` more or less like an ` ExecuteMsg ` ,
288- including calling into other contracts.
280+ contains all information needed to process the receipt. This info has already
281+ been verified by the core IBC modules via light client and merkle proofs. It
282+ guarantees all metadata in the ` IbcPacket ` structure is valid, and the ` data `
283+ field was written on the remote chain. Furthermore, it guarantees that the
284+ packet is processed at most once (zero times if it times out). Fields like
285+ ` dest.channel_id ` and ` sequence ` have a similar trust level to ` MessageInfo ` ,
286+ which we use to authorize normal transactions. The ` data ` field should be
287+ treated like the ` ExecuteMsg ` data, which is only as valid as the entity that
288+ signed it.
289+
290+ You can generally ignore ` timeout_* ` (this entry point is only called if it
291+ hasn't yet timed out) and ` sequence ` (which is used by the IBC framework to
292+ avoid duplicates). I generally use ` dest.channel_id ` like ` info.sender ` to
293+ authenticate the packet, and parse ` data ` into a ` PacketMsg ` structure, using
294+ the same encoding rules as we discussed in the last section. After that you can
295+ process ` PacketMsg ` more or less like an ` ExecuteMsg ` , including calling into
296+ other contracts.
289297
290298``` rust
291299#[derive(Serialize , Deserialize , Clone , Debug , PartialEq , JsonSchema )]
@@ -334,16 +342,16 @@ After quite some
334342we struggled to map this idea to the CosmWasm model. However, we also discovered
335343a deep similarity between these requirements and the
336344[ submessage semantics] ( ./SEMANTICS.md#submessages ) . It just requires some
337- careful coding on the contract developer's side to new throw errors. This
338- produced 3 suggests on how to handle errors and rollbacks _ inside
345+ careful coding on the contract developer's side to not throw errors. This
346+ produced 3 suggestions on how to handle errors and rollbacks _ inside
339347` ibc_packet_receive ` _
340348
3413491 . If the message doesn't modify any state directly, you can simply put the
342350 logic in a closure, and capture errors, converting them into error
343351 acknowledgements. This would look something like the
344352 [ main dispatch loop in ` ibc-reflect ` ] ( https://github.com/CosmWasm/cosmwasm/blob/cd784cd1148ee395574f3e564f102d0d7b5adcc3/contracts/ibc-reflect/src/contract.rs#L217-L248 ) :
345353
346- ``` rust
354+ ``` rust
347355 (|| {
348356 // which local channel did this packet come on
349357 let caller = packet . dest. channel_id;
@@ -365,7 +373,7 @@ produced 3 suggests on how to handle errors and rollbacks _inside
365373 attributes : vec! [],
366374 })
367375 })
368- ```
376+ ```
369377
3703782 . If we modify state with an external call, we need to wrap it in a
371379 ` submessage ` and capture the error. This approach requires we use _ exactly
@@ -377,52 +385,52 @@ produced 3 suggests on how to handle errors and rollbacks _inside
377385 [ bottom of reply section] ( ./SEMANTICS.md#handling-the-reply ) ). You can see a
378386 similar example in how
379387 [ ` ibc-reflect ` handles ` receive_dispatch ` ] ( https://github.com/CosmWasm/cosmwasm/blob/eebb9395ccf315320e3f2fcc526ee76788f89174/contracts/ibc-reflect/src/contract.rs#L307-L336 ) .
380- Note how we use a unique reply id for this and use that to catch any
388+ Note how we use a unique reply ID for this and use that to catch any
381389 execution failure and return an error acknowledgement instead:
382390
383- ``` rust
384- fn receive_dispatch (
385- deps : DepsMut ,
386- caller : String ,
387- msgs : Vec <CosmosMsg >,
388- ) -> StdResult <IbcReceiveResponse > {
389- // what is the reflect contract here
390- let reflect_addr = accounts (deps . storage). load (caller . as_bytes ())? ;
391-
392- // let them know we're fine
393- let acknowledgement = to_binary (& AcknowledgementMsg :: <DispatchResponse >:: Ok (()))? ;
394- // create the message to re-dispatch to the reflect contract
395- let reflect_msg = ReflectExecuteMsg :: ReflectMsg { msgs };
396- let wasm_msg = wasm_execute (reflect_addr , & reflect_msg , vec! [])? ;
397-
398- // we wrap it in a submessage to properly report errors
399- let sub_msg = SubMsg {
400- id : RECEIVE_DISPATCH_ID ,
401- msg : wasm_msg . into (),
402- gas_limit : None ,
403- reply_on : ReplyOn :: Error ,
404- };
405-
406- Ok (IbcReceiveResponse {
407- acknowledgement ,
408- submessages : vec! [sub_msg ],
409- messages : vec! [],
410- attributes : vec! [attr (" action" , " receive_dispatch" )],
411- })
412- }
391+ ``` rust
392+ fn receive_dispatch (
393+ deps : DepsMut ,
394+ caller : String ,
395+ msgs : Vec <CosmosMsg >,
396+ ) -> StdResult <IbcReceiveResponse > {
397+ // what is the reflect contract here
398+ let reflect_addr = accounts (deps . storage). load (caller . as_bytes ())? ;
399+
400+ // let them know we're fine
401+ let acknowledgement = to_binary (& AcknowledgementMsg :: <DispatchResponse >:: Ok (()))? ;
402+ // create the message to re-dispatch to the reflect contract
403+ let reflect_msg = ReflectExecuteMsg :: ReflectMsg { msgs };
404+ let wasm_msg = wasm_execute (reflect_addr , & reflect_msg , vec! [])? ;
405+
406+ // we wrap it in a submessage to properly report errors
407+ let sub_msg = SubMsg {
408+ id : RECEIVE_DISPATCH_ID ,
409+ msg : wasm_msg . into (),
410+ gas_limit : None ,
411+ reply_on : ReplyOn :: Error ,
412+ };
413+
414+ Ok (IbcReceiveResponse {
415+ acknowledgement ,
416+ submessages : vec! [sub_msg ],
417+ messages : vec! [],
418+ attributes : vec! [attr (" action" , " receive_dispatch" )],
419+ })
420+ }
413421
414- #[entry_point]
415- pub fn reply (deps : DepsMut , _env : Env , reply : Reply ) -> StdResult <Response > {
416- match (reply . id, reply . result) {
417- (RECEIVE_DISPATCH_ID , ContractResult :: Err (err )) => Ok (Response {
418- data : Some (encode_ibc_error (err )),
419- .. Response :: default ()
420- }),
421- (INIT_CALLBACK_ID , ContractResult :: Ok (response )) => handle_init_callback (deps , response ),
422- _ => Err (StdError :: generic_err (" invalid reply id" )),
422+ #[entry_point]
423+ pub fn reply (deps : DepsMut , _env : Env , reply : Reply ) -> StdResult <Response > {
424+ match (reply . id, reply . result) {
425+ (RECEIVE_DISPATCH_ID , ContractResult :: Err (err )) => Ok (Response {
426+ data : Some (encode_ibc_error (err )),
427+ .. Response :: default ()
428+ }),
429+ (INIT_CALLBACK_ID , ContractResult :: Ok (response )) => handle_init_callback (deps , response ),
430+ _ => Err (StdError :: generic_err (" invalid reply id or result" )),
431+ }
423432 }
424- }
425- ```
433+ ```
426434
4274353 . For a more complex case, where we are modifying local state and possibly
428436 sending multiple messages, we need to do a self-call via submessages. What I
@@ -441,22 +449,22 @@ pub fn reply(deps: DepsMut, _env: Env, reply: Reply) -> StdResult<Response> {
441449 pieces we already have. For clarity, the ` reply ` statement should look
442450 something like:
443451
444- ``` rust
445- #[entry_point]
446- pub fn reply (_deps : DepsMut , _env : Env , reply : Reply ) -> StdResult <Response > {
447- if reply . id != DO_IBC_RECEIVE_ID {
448- return Err (StdError :: generic_err (" invalid reply id" ));
449- }
450- let data = match reply . result {
451- ContractResult :: Ok (response ) => response . data,
452- ContractResult :: Err (err ) => Some (encode_ibc_error (err )),
453- };
454- Ok (Response {
455- data ,
456- .. Response :: default ()
457- })
458- }
459- ```
452+ ``` rust
453+ #[entry_point]
454+ pub fn reply (_deps : DepsMut , _env : Env , reply : Reply ) -> StdResult <Response > {
455+ if reply . id != DO_IBC_RECEIVE_ID {
456+ return Err (StdError :: generic_err (" invalid reply id" ));
457+ }
458+ let data = match reply . result {
459+ ContractResult :: Ok (response ) => response . data,
460+ ContractResult :: Err (err ) => Some (encode_ibc_error (err )),
461+ };
462+ Ok (Response {
463+ data ,
464+ .. Response :: default ()
465+ })
466+ }
467+ ```
460468
461469##### Standard Acknowledgement Envelope
462470
0 commit comments