Skip to content

Commit 93dcdb2

Browse files
committed
chore: split semantics.mdx and distribute to other chapters
1 parent 0d65983 commit 93dcdb2

File tree

6 files changed

+170
-255
lines changed

6 files changed

+170
-255
lines changed

Diff for: src/pages/core/_meta.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@
55
"standard-library": "Standard Library",
66
"conventions": "Conventions",
77
"advanced": "Advanced",
8-
"specification": "Specification",
9-
"semantics": "Semantics"
8+
"specification": "Specification"
109
}

Diff for: src/pages/core/architecture/_meta.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"semantics": "Semantics",
23
"actor-model": "Actor Model",
34
"events": "Events",
45
"gas": "Gas",

Diff for: src/pages/core/architecture/semantics.mdx

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
tags: ["core"]
3+
---
4+
5+
# Contract Semantics
6+
7+
This document provides an explanation of the semantics governing the interaction between a CosmWasm
8+
contract and its environment.
9+
10+
## Definitions
11+
12+
**Contract** is a [WebAssembly](https://webassembly.org/) code stored in the blockchain's state.
13+
This has no state except that which is contained in the binary code (eg. static constants).
14+
15+
**Instance** refers to a specific instantiation of a contract. It includes a reference to the
16+
contract's binary as well as a state unique to the instance, which is initialized upon its creation.
17+
This state is stored in the key-value store on the blockchain's state. Consequently, a reference to
18+
the contract's binary, combined with a reference to the prefixed data store, uniquely identifies the
19+
smart contract.
20+
21+
Example: we could upload a generic "ERC20 mintable" contract, and many people could create
22+
independent instances based on the same bytecode, where the local data defines the token name, the
23+
issuer, the max issuance, etc.
24+
25+
1. First you **store** a _contract_,
26+
2. Then you **instantiate** an _instance_,
27+
3. Finally users **invoke** the _instance_.
28+
29+
### SDK Context
30+
31+
Before looking at CosmWasm, we should look at the semantics enforced by the blockchain framework we
32+
integrate with - the [Cosmos SDK](https://v1.cosmos.network/sdk). It is based upon the
33+
[Tendermint BFT](https://tendermint.com/core/) Consensus Engine. Let us first look how they process
34+
transactions before they arrive in CosmWasm.
35+
36+
First, the Tendermint engine will seek >2/3 consensus on a list of transactions to be included in
37+
the next block. This is done _without executing them_. They are simply subjected to a minimal
38+
pre-filter by the Cosmos SDK module, to ensure they are validly formatted transactions, with
39+
sufficient gas fees, and signed by an account with sufficient fees to pay it. Notably, this means
40+
many transactions that error may be included in a block.
41+
42+
Once a block is committed, the transactions are then fed to the Cosmos SDK sequentially in order to
43+
execute them. Each one returns a result or error along with event logs, which are recorded in the
44+
`TxResults` section of the next block. The `AppHash` (or merkle proof or blockchain state) after
45+
executing the block is also included in the next block.
46+
47+
The Cosmos SDK `BaseApp` handles each transaction in an isolated context. It first verifies all
48+
signatures and deducts the gas fees. It sets the "Gas Meter" to limit the execution to the amount of
49+
gas paid for by the fees. Then it makes an isolated context to run the transaction. This allows the
50+
code to read the current state of the chain (after the last transaction finished), but it only
51+
writes to a cache, which may be committed or rolled back on error.
52+
53+
A transaction may consist of multiple messages and each one is executed in turn under the same
54+
context and same gas limit. If all messages succeed, the context will be committed to the underlying
55+
blockchain state and the results of all messages will be stored in the `TxResult`. If one message
56+
fails, all later messages are skipped and all state changes are reverted. This is very important for
57+
atomicity. That means Alice and Bob can both sign a transaction with 2 messages: Alice pays Bob 1000
58+
ATOM, Bob pays Alice 50 ETH, and if Bob doesn't have the funds in his account, Alice's payment will
59+
also be reverted. This is similar to how a database transaction typically works.
60+
61+
[`x/wasm`](https://github.com/CosmWasm/wasmd/tree/master/x/wasm) is a custom Cosmos SDK module,
62+
which processes certain messages and uses them to upload, instantiate, and execute smart contracts.
63+
It accepts a properly signed
64+
[`CosmWasm message`](https://github.com/CosmWasm/wasmd/blob/master/proto/cosmwasm/wasm/v1/tx.proto),
65+
routes it to [`Keeper`](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/keeper.go),
66+
which loads the proper smart contract and calls one of the entry-point on it. Note that this method
67+
may either return a success (with data and events) or an error. In the case of an error here, it
68+
will revert the entire transaction in the block.
69+
70+
For more information on contracts design visit [entry points chapter](../entrypoints.mdx).

Diff for: src/pages/core/architecture/transactions.mdx

+74
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,77 @@ error, retry the operation, ignore it, etc.
2828

2929
The default value `ReplyOn::Success` means the caller is not ready to handle an error in the message
3030
execution and the entire transaction is reverted on error.
31+
32+
## Dispatching Submessages
33+
34+
Now let's move onto the `messages` field of the
35+
[`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html). Some contracts
36+
are fine only talking with themselves. But many want to move tokens or call into other contracts for
37+
more complex actions. This is where messages come in. We return
38+
[`CosmosMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.CosmosMsg.html), which is a
39+
serializable representation of any external call the contract can make.
40+
41+
This may be hard to understand at first. "Why can't I just call another contract?", you may ask.
42+
However, we do this to prevent one of the most widespread and hardest to detect security holes in
43+
Ethereum contracts - reentrancy. We do this by following the actor model, which doesn't nest
44+
function calls, but returns messages that will be executed later. This means all state that is
45+
carried over between one call and the next happens in storage and not in memory. For more
46+
information on this design, I recommend you read [our docs on the Actor Model](actor-model.mdx).
47+
48+
A common request was the ability to get the result from one of the messages you dispatched. For
49+
example, you want to create a new contract with
50+
[`WasmMsg::Instantiate`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.WasmMsg.html#variant.Instantiate),
51+
but then you need to store the address of the newly created contract in the caller. This is possible
52+
with `messages` and replies. This makes use of
53+
[`CosmosMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.CosmosMsg.html) as above, but it
54+
wraps it inside a [`SubMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsg.html)
55+
envelope.
56+
57+
What are the semantics of a submessage execution? First, we create a sub-transaction context around
58+
the state, allowing it to read the latest state written by the caller, but write to yet-another
59+
cache. If `gas_limit` is set, it is sandboxed to how much gas it can use until it aborts with
60+
`OutOfGasError`. This error is caught and returned to the caller like any other error returned from
61+
contract execution (unless it burned the entire gas limit of the transaction).
62+
63+
If it returns success, the temporary state is committed (into the caller's cache), and the
64+
[`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html) is processed as
65+
normal. Once the response is fully processed, this may then be intercepted by the calling contract
66+
(for `ReplyOn::Always` and `ReplyOn::Success`). On an error, the subcall will revert any partial
67+
state changes due to this message, but not revert any state changes in the calling contract. The
68+
error may then be intercepted by the calling contract (for `ReplyOn::Always` and `ReplyOn::Error`).
69+
In this case, the message's error doesn't abort the whole transaction.
70+
71+
Note, that error doesn't abort the whole transaction _if and only if_ the `reply` is called - so in
72+
case of `ReplyOn::Always` and `ReplyOn::Error`. If the submessage is called with `ReplyOn::Success`
73+
or `ReplyOn::Never`, the error in a subsequent call would result in failing whole transaction and
74+
not commit the changes for it. The rule here is as follows: if for any reason you want your message
75+
handling to succeed on submessage failure, you always have to reply on failure.
76+
77+
## Order of execution and rollback procedure
78+
79+
Submessages handling follows _depth first_ order rules. Let's see the following example scenario:
80+
81+
```mermaid
82+
83+
sequenceDiagram
84+
Note over Contract1: Contract1 returns two submessages:<br/> 1. Execute Contract2<br/> 2. Execute Contract4
85+
Contract1->>Contract2: 1. Execute
86+
Note over Contract2: Contract2 returns one submessage:<br/> 1. Execute Contract3
87+
Contract2->>Contract3: 2. Execute
88+
Contract3->>Contract2: 3. Response
89+
Note over Contract2: Contract2 can handle the Response<br/>in the reply entrypoint or leave it
90+
Contract2->>Contract1: 4. Response
91+
Note over Contract1: Contract1 can handle the Response<br/>in the reply entrypoint or leave it
92+
Contract1->>Contract4: 5. Execute
93+
Contract4->>Contract1: 6. Response
94+
Note over Contract1: Contract1 can handle the Response<br/>in the reply entrypoint or leave it
95+
96+
```
97+
98+
**Note1:** The field `data` of the submessages field in the response are not forwarded down the call
99+
path. It means that for e.g. if `Contract2` will not explicitly handle response from `Contract3` and
100+
forward any data, then `Contract1` will never learn about results from `Contract3`.
101+
102+
**Note2:** If `Contract2` returns an error, the error message can be handled by the `Contract1`
103+
reply entry-point and prevent the whole transaction from rollback. In such a case only the
104+
`Contract2` and `Contract3` states changes are reverted.

Diff for: src/pages/core/entrypoints/reply.mdx

+24
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,29 @@ pub fn reply(deps: DepsMut, env: Env, msg: cosmwasm_std::Reply) -> StdResult<Res
6969
}
7070
```
7171

72+
## Handling the reply
73+
74+
Once the submessage handling is finished, the caller will get a chance to handle the result. It will
75+
get the original `id` of the subcall and the `Result` of the execution, both success and error. Note
76+
that it includes all events returned by the submessage, which applies to native sdk modules (like
77+
Bank) as well as the contracts. If you need more state, you must save it in the local store during
78+
the `execute` entry-point call, and load it in `reply`.
79+
80+
The `reply` call may return `Err` itself, in which case it is treated like the caller errored, and
81+
aborting the sub-transaction. However, on successful processing, `reply` may return a normal
82+
[`Response`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html), which will be
83+
processed as normal - events added to the `EventManager`, and all `messages` dispatched as described
84+
above. When `Err` is returned by a message handler, all changes made by the handler up to the reply
85+
entry-point that returns the `Ok` response are reverted. More information can be found in the
86+
following section.
87+
88+
The responses emitted by the submessage are gathered in the
89+
[`msg_responses`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsgResponse.html#structfield.msg_responses)
90+
field of the
91+
[SubMsgResponse](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsgResponse.html)
92+
structure. **Wasmd** allows chains to translate a single contract message into multiple SDK
93+
messages. In that case all the message responses from each are concatenated into this flattened
94+
`Vec`.
95+
7296
[its own page]: ../architecture/actor-model
7397
[transactions]: ../architecture/transactions

0 commit comments

Comments
 (0)