Skip to content

Commit

Permalink
Merge pull request #4 from CosmWasm/minor-review-remarks
Browse files Browse the repository at this point in the history
Minor review remarks
  • Loading branch information
jawoznia authored Nov 8, 2023
2 parents 9e8eab2 + b142717 commit 52f092e
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 133 deletions.
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
# The Sylvia Book

This book is about writing Smart Contracts using [Sylvia](https://github.com/CosmWasm/sylvia) framework.
This book is about writing **Smart Contracts** using [Sylvia](https://github.com/CosmWasm/sylvia) framework.

To learn about CosmWasm on which Sylvia rely check [The Cosmwasm Book](https://book.cosmwasm.com/index.html)
To learn about [CosmWasm](https://github.com/CosmWasm),
on which Sylvia relies, please check [The CosmWasm Book](https://book.cosmwasm.com).

## About

This repo contains source code for [The Sylvia Book](https://cosmwasm.github.io/sylvia-book/).
This repo contains a source code for [The Sylvia Book](https://cosmwasm.github.io/sylvia-book/).

## Building

The book is built using [mdbook](https://github.com/rust-lang/mdBook).

The book is built using [mdBook](https://github.com/rust-lang/mdBook).
To build it, you must first install [Rust](https://www.rust-lang.org/tools/install).

Then install `mdbook` using cargo:
Having Rust installed, install `mdBook` using cargo:

```bash
$ cargo install mdbook
```

and build the book from this directory:
and then build the book from this repository:

```bash
$ mdbook build
```

To serve the book locally, run:

```bash
mdbook build
$ mdbook serve
```

For more info about using mdbook read its own [book](https://rust-lang.github.io/mdBook/index.html).
To learn more about using `mdBook`, read its own [book](https://rust-lang.github.io/mdBook/index.html).
3 changes: 0 additions & 3 deletions book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ description = "Guide to building CosmWasm smart contracts"

[rust]
edition = "2021"

[preprocessor.plantuml]
plantuml-cmd = "plantuml"
32 changes: 16 additions & 16 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,24 @@ It will lead you step by step and explain relevant topics from easiest to tricki

The idea of the book is not only to tell you about smart contract development but also
to show you how to do it clean and maintainable. I will show you some good practices
for using `sylvia`.
for using `Sylvia`.

This book is not meant to teach you about the `CosmWasm`. To learn about that, I recommend reading
[the cosmwasm-book](https://book.cosmwasm.com/).
This book is not meant to teach you about the `CosmWasm`.
To learn about that, read [The CosmWasm Book](https://book.cosmwasm.com).

This book covers `sylvia` in version 0.7.0.
This book covers `Sylvia` in version 0.7.0.

## Prerequirements
## Prerequisites

This book explores CosmWasm smart contracts. It is not a Rust tutorial, and it
assumes basic Rust knowledge. As you will probably learn it alongside this
book, I recommend first grasping the language. You can find
great resources to start with Rust on [Learn
Rust](https://www.rust-lang.org/learn) page.
This book explores CosmWasm smart contracts.
It is not intended to be a Rust tutorial, and it assumes a basic Rust knowledge.
As you will probably learn it alongside this book, I recommend first grasping the language.
You can find great resources to start with Rust on [Learn Rust](https://www.rust-lang.org/learn) page.

## CosmWasm API documentation

This is the guide-like documentation. If you are looking for the API
documentation, you may be interested in checking one of the following:
This is the guide-like documentation. If you are looking for the API documentation,
you may be interested in checking one of the following:

- [cosmwasm-std](https://crates.io/crates/cosmwasm-std)
- [cw-storage-plus](https://crates.io/crates/cw-storage-plus)
Expand All @@ -33,10 +32,11 @@ documentation, you may be interested in checking one of the following:

## Contributing to the book

This book is maintained on [Github](https://github.com/CosmWasm/sylvia-book) and auto
deployed from there. Please create an
[issue](https://github.com/CosmWasm/sylvia-book/issues) or pull request if you find
any mistakes, bugs, or ambiguities.
This book is maintained on [GitHub](https://github.com/CosmWasm/sylvia-book)
and auto deployed from there.
Please create an [issue](https://github.com/CosmWasm/sylvia-book/issues)
or pull request if you find any mistakes, bugs, or ambiguities.

## Warning

This book is still under construction, so be aware that, in some places, it might feel disjointed.
4 changes: 2 additions & 2 deletions src/basics.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Basics

This chapter will go through creating basic smart contract step by step.
I will explain the core features of `sylvia` and some good practices.
This chapter will guide you through creating basic smart contract, step by step.
I will explain the core features of `Sylvia` framework and some good practices.
34 changes: 19 additions & 15 deletions src/basics/building-contract.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
# Building the contract

Now that our contract correctly compiles into wasm, let's digest our build command.
Now that our contract correctly compiles into Wasm, let's digest our build command.

```
```shell
$ cargo build --target wasm32-unknown-unknown --release --lib
```

The `--target` argument tells cargo to perform cross-compilation for a given target instead of
building a native binary for an OS, it is running on - in this case, `wasm32-unknown-unknown`,
The `--target` argument tells cargo to perform cross-compilation for a given target, instead of
building a native binary for an OS it is running on. In this case the target is `wasm32-unknown-unknown`,
which is a fancy name for Wasm target.

Contract would be properly created without `--lib`, but later, when we add `query`, it will be
needed so adding this argument from the beginning is a good idea.
Our contract would be also properly compiled without `--lib` flag, but later, when we add `query`,
this flag will be required, so using it from the beginning is a good habit.

Additionally, I passed the `--release` argument to the command - it is not
required, but in most cases, debug information is not very useful while running
on-chain. It is crucial to reduce the uploaded binary size for gas cost
minimization. It is worth knowing that there is a [CosmWasm Rust
Optimizer](https://github.com/CosmWasm/rust-optimizer) tool that takes care of
building even smaller binaries. For production, all the contracts should be compiled using this
tool, but it is not an essential thing to do for learning purposes.
tool, but it is now not essential for learning purposes.

## Aliasing build command

Now I see you are disappointed in building your contracts with some overcomplicated command
instead of simple `cargo build`. Hopefully, it is not the case. The common practice is to alias
the building command to make it as simple as building a native app.
the building command, to make it as simple as building a native application.

Let's create the `.cargo/config` file in your contract project directory with the following content:
Let's create `.cargo/config` file in your contract project directory with the following content:

```toml
[alias]
wasm = "build --target wasm32-unknown-unknown --release --lib"
wasm-debug = "build --target wasm32-unknown-unknown --lib"
```

Building your Wasm binary is as easy as executing `cargo wasm`. We also added the additional
`wasm-debug` command for rare cases when we want to build the wasm binary, including debug information.
Building your Wasm binary is now as easy as executing `cargo wasm`. We also added the additional
`wasm-debug` command for rare cases, when we want to build the Wasm binary with debug information included.

## Checking contract validity

When the contract is built, the last step is to ensure it is a valid CosmWasm contract is to call
`cosmwasm-check` on it:
When the contract is built, the last step to ensure that it is a valid CosmWasm contract
is to call `cosmwasm-check` on it:

```
```shell
$ cargo wasm
...
.
. (compilation messages)
.
Finished release [optimized] target(s) in 0.03s

$ cosmwasm-check target/wasm32-unknown-unknown/release/contract.wasm
Available capabilities: {"cosmwasm_1_1", "iterator", "staking", "stargate"}

Expand Down
39 changes: 20 additions & 19 deletions src/basics/create-project.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Create a Rust project

As smart contracts are Rust library crates, we will start with creating one:
Smart contracts are Rust library crates. We will start with creating one:

```
```shell
$ cargo new --lib ./contract
```

You created a simple Rust library, but it is not yet ready to be a smart contract. The first thing
to do is to update the `Cargo.toml` file:
You created a simple Rust library, but it is not yet ready to be a smart contract.
The first thing to do is to update the `Cargo.toml` file:

```toml
[package]
Expand All @@ -26,26 +26,27 @@ cosmwasm-schema = "1.3.1"
serde = "1.0.180"
```

As you can see, I added a `crate-type` field for the library section. Generating the
[`cdylib`](https://doc.rust-lang.org/reference/linkage.html) is
required to create a proper web assembly binary. The downside of this is that such a library cannot
be used as a dependency for other Rust crates - for now, it is not needed, but later we will show
As you can see, I added a `crate-type` field for the library section.
Generating the [`cdylib`](https://doc.rust-lang.org/reference/linkage.html) is
required to create a proper web assembly binary.
The downside of this is that such a library cannot be used as a dependency
for other Rust crates - for now, it is not needed, but later we will show
how to approach reusing contracts as dependencies.

Additionally, we added some core dependencies for smart contracts:
- [`cosmwasm-std`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/). This crate is a
- [`cosmwasm-std`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/) - Crate that is a
standard library for smart contracts. It provides essential utilities for communication with the
outside world, helper functions, and types. Every smart contract we will build will
use this dependency.
- [`sylvia`](https://docs.rs/sylvia/0.7.0/sylvia/) - the crate we will learn in this
book. It provides us with three procedural macros: `entry_points`, `contract` and `interface`. I
will expand on them later in the book.
- [`schemars`](https://docs.rs/schemars/0.8.12/schemars/index.html) - crate used to create JSON
schema documents for our contracts. It is automatically derived on types
generated by `sylvia` and will be later used to provide nice API blockchain users who might not be
rust devs.
- [`cosmwasm-schema`](https://docs.rs/cosmwasm-schema/1.3.1/cosmwasm_schema/) - similiar
to schemars. This crate expands on `schemars` and provides us with trait
- [`sylvia`](https://docs.rs/sylvia/0.7.0/sylvia/) - Crate, we will learn in this
book. It provides us with three procedural macros: `entry_points`, `contract` and `interface`.
I will expand on them later in the book.
- [`schemars`](https://docs.rs/schemars/0.8.12/schemars/index.html) - Crate used to create JSON
schema documents for our contracts. It is automatically derived on types generated by
`sylvia` and will be later used to provide concise API for blockchain users, who might not be Rust developers.
- [`cosmwasm-schema`](https://docs.rs/cosmwasm-schema/1.3.1/cosmwasm_schema/) - Similar to `schemars`.
This crate expands on `schemars` and provides us with trait
[`QueryResponses`](https://docs.rs/cosmwasm-schema/1.3.1/cosmwasm_schema/trait.QueryResponses.html)
which ties query variants to their responses. I will expand on that later in the book.
- [`serde`](https://docs.rs/serde/1.0.180/serde/) -
- [`serde`](https://docs.rs/serde/1.0.180/serde/) - Framework for serializing and deserializing
Rust data structures efficiently and generically.
41 changes: 21 additions & 20 deletions src/basics/entry-points.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@

Typical Rust application starts with the `fn main()` function called by the operating system.
Smart contracts are not significantly different. When the message is sent to the contract, a
function called "entry point" is called. Unlike native applications, which have only a single
`main` entry point, smart contracts have a couple corresponding to different message types:
`instantiate`, `execute`, `query`, `sudo`, `migrate` and more.
function called "entry point" is executed. Unlike native applications, which have only a single
`main` entry point, smart contracts have a couple of them, each corresponding to different
message type: `instantiate`, `execute`, `query`, `sudo`, `migrate` and more.

To start, we will go with three basic entry points:

- `instantiate` is called once per smart contract lifetime - you can think about it as
- **`instantiate`** is called once per smart contract lifetime; you can think about it as
a constructor or initializer of a contract.
- `execute` for handling messages which can modify contract state - they are used to
- **`execute`** for handling messages which can modify contract state; they are used to
perform some actual actions.
- `query` for handling messages requesting some information from a contract; unlike `execute`,
they can never affect any contract state, and are used just like database queries.
- **`query`** for handling messages requesting some information from a contract; unlike **`execute`**,
they can never alter any contract state, and are used in a similar manner to database queries.

## Generate entry points

`Sylvia` provides us with [`entry_points`](https://docs.rs/sylvia/0.7.0/sylvia/attr.entry_points.html)
attribute macro. In most cases, your entry point will just dispatch received messages to the handler,
`Sylvia` provides an attribute macro named [`entry_points`](https://docs.rs/sylvia/0.7.0/sylvia/attr.entry_points.html).
In most cases, your entry point will just dispatch received messages to the handler,
so it's not necessary to manually create them, and we can rely on a macro to do that for us.

Let's add the attribute macro to our contract:
Let's add the **`entry_points`** attribute macro to our contract:

```
```rust,noplayground
use cosmwasm_std::{Response, StdResult};
use sylvia::types::InstantiateCtx;
use sylvia::{contract, entry_points};
Expand All @@ -44,21 +44,22 @@ impl CounterContract {
}
```

Note that `#[entry_points]` is added above the `#[contract]`. This is because `contract` removes
the attributes such as `#[msg(...)]` on which both those macros rely. Remember to always place
`#[entry_points]` first.
Note that **`#[entry_points]`** is added above the **`#[contract]`**.
It is because **`#[contract]`** removes attributes like **`#[msg(...)]`** on which both these macros rely.

Always remember to place **`#[entry_points]`** first.

`Sylvia` generates the entry_points with [`#[entry_point]`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/attr.entry_point.html)
attribute macro. Its purpose is to wrap the whole entry point to the form Wasm runtime understands.
`Sylvia` generates entry points with [`#[entry_point]`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/attr.entry_point.html)
attribute macro. Its purpose is to wrap the whole entry point to the form the Wasm runtime understands.
The proper Wasm entry points can use only basic types supported natively by Wasm specification, and
Rust structures and enums are not in this set. Working with such entry points would be
overcomplicated, so CosmWasm creators delivered the `entry_point` macro. It creates the raw Wasm
entry point, calling the decorated function internally and doing all the magic required to build our
high-level Rust arguments from arguments passed by Wasm runtime.

Now that our contract has a proper `entry point` let's build it and check if it's properly defined.
Now, when our contract has a proper entry point, let's build it and check if it's correctly defined:

```
```shell
contract $ cargo build --release --target wasm32-unknown-unknown --lib
Finished release [optimized] target(s) in 0.03s

Expand All @@ -72,5 +73,5 @@ All contracts (1) passed checks!

## Next step

Nice! We have a proper `CosmWasm` contract. Now let's add some state to it so it will actually be
able to do something.
Well done! We have now a proper `CosmWasm` contract.
Let's add some state to it, so it will actually be able to do something.
30 changes: 21 additions & 9 deletions src/basics/first-messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,38 @@ attribute macro. It will parse every method inside the `impl` block marked with
attribute and create proper messages and utilities like `multitest helpers` for them.
More on them later.

`CosmWasm` contract requires only the `instantiate` `entry_point`, and it is mandatory to specify
`CosmWasm` contract requires only the `instantiate` entry point, and it is mandatory to specify
it for the `contract` macro. We have to provide it with the proper context type
[`InstantiateCtx`](https://docs.rs/sylvia/0.7.0/sylvia/types/struct.InstantiateCtx.html).

Context gives us access to the blockchain state, information about our contract, and the sender of the
message. We return the [`StdResult`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/type.StdResult.html)
which uses standard `CosmWasm` error
[`StdError`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/enum.StdError.html).
It's generic over [`Response`](https://docs.rs/cosmwasm-std/1.3.1/cosmwasm_std/struct.Response.html).
For now, we will return the `default` value of it.

I recommend expanding the macro now and seeing what `sylvia` generates. It might be overwhelming
as there will be a lot of things generated that seem not relevant to our code, so for the bare
minimum check the `InstantiateMsg` and its impl block.
I recommend expanding the macro now and seeing what `Sylvia` generates.
It might be overwhelming, as there will be a lot of things generated that seem not relevant to our code,
so for the bare minimum check the `InstantiateMsg` and its `impl` block.

## Next step
If we will build our contract with `cargo build --release --target wasm32-unknown-unknown --lib`
and run the `cosmwasm-check target/wasm32-unknown-unknown/release/contract.wasm`, it will fail with

If we build our contract with command:

```shell
contract $ cargo build --release --target wasm32-unknown-unknown --lib
```
contract & cosmwasm-check target/wasm32-unknown-unknown/release/contract.wasm

and then run:

```shell
contract $ cosmwasm-check target/wasm32-unknown-unknown/release/contract.wasm
```

**IT WILL FAIL** with message:

```shell
Available capabilities: {"cosmwasm_1_2", "iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_3"}

target/wasm32-unknown-unknown/release/contract.wasm: failure
Expand All @@ -73,5 +85,5 @@ Error during static Wasm validation: Wasm contract doesn't have required export:
Passes: 0, failures: 1
```
This is because our contract is not yet complete. We defined the message that could be sent to it but
didn't provide any `entry_point`. In the next chapter, we will finally make it the proper contract.
This is because our contract **IS NOT YET COMPLETE**. We defined the message that could be sent to it but
didn't provide any `entry_point`. In the next chapter, we will finally make it a proper contract.
Loading

0 comments on commit 52f092e

Please sign in to comment.