Skip to content

Commit

Permalink
Edits(?) & fixes (#183)
Browse files Browse the repository at this point in the history
* Update tests.rs

I guess this one will need to be copied to all of the future steps

* Update README.md

* Update README.md

* Update README.md

* Update lib.rs

* Update lib.rs

id suddenly changes to dna in the next step with no mention of it

* Update impls.rs

* Update README.md

Couldn't create a kitty struct in tests.rs without making the struct fields public

* Update tests.rs

* Update README.md

* Update impls.rs

* Update impls.rs

* Update impls.rs

* Update impls.rs

* Update impls.rs

* Update README.md

* Update README.md

* Update tests.rs

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update impls.rs

* Update README.md

* remove "and sex"

* Update steps/20/README.md

* Update steps/20/README.md

* Update steps/22/src/lib.rs

* Update steps/38/src/impls.rs

* Update steps/38/src/impls.rs

* Update steps/52/README.md

* Update steps/52/src/impls.rs

* Update steps/6/README.md

---------

Co-authored-by: Shawn Tabrizi <[email protected]>
  • Loading branch information
Yung-Beef and shawntabrizi authored Nov 1, 2024
1 parent 4cdd230 commit a653ddc
Show file tree
Hide file tree
Showing 16 changed files with 36 additions and 22 deletions.
2 changes: 1 addition & 1 deletion steps/11/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ These properties make hash functions key for ensuring data integrity and uniquen

Due to the properties of a Hash, it is often referred to as a fingerprint.

For context, a 32-byte hash has 2^32 different possible outputs. This nearly as many atoms as there are in the whole universe!
For context, a 32-byte hash has 2^32 different possible outputs. This is nearly as many atoms as there are in the whole universe!

This uniqueness property helps blockchain nodes come to consensus with one another.

Expand Down
2 changes: 1 addition & 1 deletion steps/16/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

If you look into the history of "hacks" and "bugs" that happen in the blockchain world, a lot of it is associated with some kind of "unsafe" code.

Keeping our blockchain logic safe, and Rust is designed to handle it well.
We need to keep our blockchain logic safe, and Rust is designed to handle it well.

## Errors

Expand Down
2 changes: 2 additions & 0 deletions steps/20/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Each `Key` can store a separate `Value`, which makes maps super useful.

In this case `[u8; 32]` represents some unique identifier for each Kitty we will store, and `()` is simply a placeholder type for now.

Note that each storage item needs its own `#[pallet::storage]` attribute.

## Conceptual

The key difference between a `StorageValue` and a `StorageMap` is:
Expand Down
4 changes: 2 additions & 2 deletions steps/22/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use super::*;
use frame::prelude::*;

impl<T: Config> Pallet<T> {
/* 🚧 TODO 🚧: Update this function signature to include `id` which is type `[u8; 32]`. */
/* 🚧 TODO 🚧: Update this function signature to include `dna` which is type `[u8; 32]`. */
pub fn mint(owner: T::AccountId) -> DispatchResult {
let current_count: u32 = CountForKitties::<T>::get();
let new_count = current_count.checked_add(1).ok_or(Error::<T>::TooManyKitties)?;
/* 🚧 TODO 🚧: In the `Kitties` map, under the key `id`, insert `()`. */
/* 🚧 TODO 🚧: In the `Kitties` map, under the key `dna`, insert `()`. */
CountForKitties::<T>::set(new_count);
Self::deposit_event(Event::<T>::Created { owner });
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions steps/22/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ pub mod pallet {
pub fn create_kitty(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
/* 🚧 TODO 🚧:
- Create `const default_id`, which type `[u8; 32]` and has value `[0u8; 32]`.
- Pass `default_id` to the `mint` function as a second parameter.
- Create a `dna` variable for this kitty, which we will set as `[0u8; 32]` for now.
- Pass `dna` to the `mint` function as the second parameter.
*/
Self::mint(who)?;
Ok(())
Expand Down
18 changes: 9 additions & 9 deletions steps/27/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ Creating a new struct in Rust is pretty straight forward.

```rust
pub struct Kitty {
dna: [u8; 32],
owner: u32,
pub dna: [u8; 32],
pub owner: u32,
}
```

Expand Down Expand Up @@ -38,18 +38,18 @@ The first, and most verbose option in our situation is to make the struct generi

```rust
pub struct Kitty<AccountId> {
dna: [u8; 32],
owner: AccountId,
pub dna: [u8; 32],
pub owner: AccountId,
}
```

If we want to use multiple generic types, we could just keep extending this pattern:

```rust
pub struct Kitty<AccountId, BlockNumber> {
dna: [u8; 32],
owner: AccountId,
created: BlockNumber,
pub dna: [u8; 32],
pub owner: AccountId,
pub created: BlockNumber,
}
```

Expand All @@ -69,8 +69,8 @@ Let's look how that might look like:

```rust
pub struct Kitty<T: Config> {
dna: [u8; 32],
owner: T::AccountId,
pub dna: [u8; 32],
pub owner: T::AccountId,
}
```

Expand Down
3 changes: 3 additions & 0 deletions steps/27/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type Block = frame_system::mocking::MockBlock<TestRuntime>;
// We create the constants `ALICE` and `BOB` to make it clear when we are representing users below.
const ALICE: u64 = 1;
const BOB: u64 = 2;
/* 🚧 TODO 🚧:
- Create `const DEFAULT_KITTY` with a `dna` of [0u8; 32] and an `owner` of 0 };.
*/

// Our blockchain tests only need 3 Pallets:
// 1. System: Which is included with every FRAME runtime.
Expand Down
2 changes: 1 addition & 1 deletion steps/31/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ let unique_payload = (item1, item2, item3);
// To use the `hash_of` API, we need to bring the `Hash` trait into scope.
use frame::traits::Hash;
// Hash that object to get a unique identifier.
let hash: [u8; 32] = BlakeTwo256::hash_of(&unique_payload).into().
let hash: [u8; 32] = BlakeTwo256::hash_of(&unique_payload).into();
```

The `hash_of` API comes from the `Hash` trait and takes any `encode`-able object, and returns a `H256`, which is a 256-bit hash. As you can see in the code above, it is easy to convert that to a `[u8; 32]` by just calling `.into()`, since these two types are equivalent.
Expand Down
2 changes: 1 addition & 1 deletion steps/38/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<T: Config> Pallet<T> {
- `kitty_id` which is `[u8; 32]`.
- It returns a `DispatchResult`
- The inner logic for now is:
- Call `Self::dispatch_event` on and emit `Event::<T>:Transferred` with params.
- Call `Self::deposit_event` and emit `Event::<T>:Transferred` with params.
- Return `Ok(())`.
*/
}
2 changes: 1 addition & 1 deletion steps/42/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ T::NativeBalance::mint_into(alice, amount)?;
T::NativeBalance::transfer(alice, bob, amount, Preserve)?;
```

The key difference here is that we do NOT assume that these APIs must from from specifically `pallet_balances`. If you wanted to use another pallet in the `polkadot-sdk` ecosystem which provides these same functions, you can use it! Our pallet is NOT tightly coupled to which pallet provides access to the `NativeBalance`, it only requires that there is something implementing the `Inspect` and `Mutate` traits.
The key difference here is that we do NOT assume that these APIs must come from specifically `pallet_balances`. If you wanted to use another pallet in the `polkadot-sdk` ecosystem which provides these same functions, you can use it! Our pallet is NOT tightly coupled to which pallet provides access to the `NativeBalance`, it only requires that there is something implementing the `Inspect` and `Mutate` traits.

The power of loose coupling may not be immediately obvious, but as you get deeper into developing in the Polkadot ecosystem, you will start to realize how powerful this approach can be.

Expand Down
1 change: 1 addition & 0 deletions steps/42/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl pallet_balances::Config for TestRuntime {
// will also need to update this configuration to represent that.
impl pallet_kitties::Config for TestRuntime {
type RuntimeEvent = RuntimeEvent;
/* 🚧 TODO 🚧: Add type `NativeBalance` as the `Balances` pallet. */
}

// We need to run most of our tests using this function: `new_test_ext().execute_with(|| { ... });`
Expand Down
2 changes: 1 addition & 1 deletion steps/44/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Let's look at how we would interact with this generic type, and solve many of th

The `Balance` type is ultimately configured inside `pallet_balances`, and remember, we don't have direct access to that pallet because we used loose coupling.

The way we can access the `Balance` type is through the `Inspect` trait of the `NativeBalance` associated type. Accessing it kind of funny, which is why we commonly introduce a `BalanceOf<T>` alias type like so:
The way we can access the `Balance` type is through the `Inspect` trait of the `NativeBalance` associated type. Accessing it is kind of funny, which is why we commonly introduce a `BalanceOf<T>` alias type like so:

```rust
// Allows easy access our Pallet's `Balance` type. Comes from `Fungible` interface.
Expand Down
2 changes: 1 addition & 1 deletion steps/46/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Set Price Extrinsic

Now that we our Pallet set up to handle balances, let's actually use them.
Now that we have our Pallet set up to handle balances, let's actually use them.

In this step, we will create an extrinsic which allows the owner of a kitty to set a price for the kitty.

Expand Down
2 changes: 1 addition & 1 deletion steps/50/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Buy Kitty Extrinsic

Now that kitties can have a price, we want to enable them to be purchaseable.
Now that kitties can have a price, we want to enable them to be purchasable.

For that, we will create the `buy_kitty` extrinsic.

Expand Down
8 changes: 7 additions & 1 deletion steps/52/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ That is all beyond the scope of this tutorial, but the high level idea is that w

In this context, we don't want someone to kill their account to buy a kitty, so we want to use `Preservation::Preserve` for our `transfer`.

> NOTE: Don't forget the TODO that imports this enum so you can use it:
>
> ```rust
> use frame::traits::tokens::Preservation;
> ```
So the final syntax should look like:
```rust
Expand All @@ -85,7 +91,7 @@ Both transfer functions need to succeed for the sale to complete successfully.

If either one of them would fail, the whole purchase should fail.

Thankfully, both of our transfer functions return a result, and to handle things correctly here, we just ned to propagate up those errors. For that, we simply include `?` at the end of the function.
Thankfully, both of our transfer functions return a result, and to handle things correctly here, we just need to propagate up those errors. For that, we simply include `?` at the end of the function.

If at any point our extrinsic or the logic inside the extrinsic returns an error, the whole extrinsic will fail and all changes to storage will be undone. This is exactly the same behavior you would expect from a smart contract, and keeps our state transition function functioning smoothly.

Expand Down
2 changes: 2 additions & 0 deletions steps/6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ If you are familiar with smart contracts or any kind of blockchain application,

Those transactions are processed, and then dispatched to callable functions within the blockchain.

For ergonomics, you will normally see callable functions defined in the `lib.rs`, but their logic implemented in a separate `impls.rs` file. This is really up to your preference, but since this is the common practice in the Polkadot SDK, the tutorial will use this pattern as well.

### Pallet Call Macro

Pallet development allows you to create callable functions by introducing the `#[pallet::call]` macro on top of a normal function implementation code block.
Expand Down

0 comments on commit a653ddc

Please sign in to comment.