Skip to content

Commit

Permalink
very rough drafts
Browse files Browse the repository at this point in the history
  • Loading branch information
CrackTheCode016 committed Oct 6, 2023
1 parent 76f4806 commit fb47642
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 16 deletions.
106 changes: 103 additions & 3 deletions docs/Rust/section2/alt-data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,112 @@ sidebar_label: Alternative Data Types
description: Learn when, and how to use non-typical data types
---

## Deterministic Types - Floating Point Numbers
Rust's primitive data types can form the basis for more complex data types. These data types are
custom, but are provided when certain primitive types are not able to accommodate some atypical
scenario.

In the Polkadot SDK, a great example of this is the `sp_arithmetic` crate, which provides minimal,
redefined primitives for basic types related to numerics specifically for Susbtrate runtimes.

`sp_core`, another crate, provides predefined types for dealing with cryptographic primitives or
large numbers. Let's explore how to access and use these data types, and why they're useful in the
context of runtime development.

:::tip Confused on what is going on? We often couple Rust with examples from the Substrate codebase.
Anytime you feel lost, make sure to read the tip right below any new concepts that are introduced!
:::

## Using Larger Data Types

When wanting to represent very large numbers, such as a _hash_ or even an elliptic-curve derived
public or private key, it often requires up to 256 bits of data. However, the Rust standard library
supplies data types up to `u128`, or 128-bit long numbers. An alternative is by using an existing
data structure, such as a `String`, however this could be costly, as well as cumbersome process when
reading it later.

These very large numbers are able to be accommodated by using external types. While these may be
slower to process, in cryptographic contexts, it allows us to represent complex numbers numerically.

Some Substrate libraries, such as `sp_core`, provide primitives for dealing with these large
numbers. Let's take a look at `U256`, aka a 256-bit integer type:

```rust
pub struct U256(pub [u64; 4]);
```

:::tip Why is a number a struct?

Because Rust cannot just simply store an entire 256-bit number in one variable, a custom data type
has to be created. This particular type, `U256`, actually stores _four_ `u64` numbers.

:::

todo: use h256 as an example?

In cryptographic contexts, this is especially, useful, as we can now represent 256-bit numbers
numerically.

## "Deterministic" Data Types - Floating Point Numbers

Floating point numbers have presented issues in traditional computing for decades. To make a long
story short, floating point calculations are not deterministic, as different architectures may
calculate the end result differently.

todo: add better sources for this

For this reason, the notion of floating point primitives, such as `f32` and `f64`, cannot, and
should not, be used in the context of the blockchain runtime. Even if one environment can
deterministically use floating point numbers with sufficient accuracy, other clients on the network
may provide alternate calculations.

## Negative Numbers - Unsigned Integers vs. Signed Integers

You may notice that Substrate specifically uses _unsigned_ for many data types which are represented
for a number, such as a `BlockNumber`, which is a `u32`, or even a balance, which is usually
represented as `u128`.

Unsigned types cannot be negative, meaning that all primitives used within a runtime are all
positive, real numbers. This is party due to a few reasons:

1. The notion of a negative balance does not exist for on-chain balances. Even for a `BlockNumber`,
a negative block number is invalid and unreasonable in any scenario.
2. `u32` and other unsigned types give a higher, _positive_ bound then a type like `i32`. With
`BlockNumber` as an example, this would allow the total amount of blocks that a network could
generate to be much higher than using a signed type.

:::tip Thought exercise: if Polkadot used `u8` for the BlockNumber type, how would the chain run
before it overflowed?

Give it some thought, and pick the correct answer. What would a _smaller_ data type imply for
something like `BlockNumber`, which the network uses to progress?

<details>
<summary>It wouldn't overflow; the error would be handled </summary>
</details>
<details>
<summary>After the limit of <code>u8::MAX</code> blocks</summary>
</details>
:::

### Context-driven types

In runtime development, data types should be chosen more carefully than normal. Because a runtime
instance is anticipated to run for a long period of time, ideally without too many breaking
upgrades, fundamental primitives and their underlying types must be able to withstand different
scenarios or network load.

They can have a direct impact on the chain itself; from the state and how those types are stored, to
the chain's continued operation and ensuring it can run for an amount of time without interruption.

## A Deeper Look at Scalar & Compound Types

### Type Aliases

## Recognizing "Sized" Types
Type aliases are used to shorten long, generic types. For example, the following is how one may
access a Balance with all configuration in Substrate:

```rust
type BalanceOf<T> == ...
```

## Larger Data Types
### Recognizing "Sized" Types
4 changes: 2 additions & 2 deletions docs/Rust/section2/common-traits.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
id: common-traits
title: Common Traits in Rust
sidebar_label: Common Traits in Rust
title: Useful Traits
sidebar_label: Useful Traits - Common Substrate Traits
description:
Learn some of the most common traits to know about, how to use them, and how they can improve your
runtime.
Expand Down
7 changes: 7 additions & 0 deletions docs/Rust/section2/extended-index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Extended Basics
---

import DocCardList from '@theme/DocCardList';

<DocCardList />
10 changes: 3 additions & 7 deletions docs/Rust/section2/safe-math.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
---
id: safe-math
title: Floating Point Numbers & Safe Math
sidebar_label: Floating Point Numbers & Safe Math
title: Using Substrate Arithmetic for Safe Math
sidebar_label: Using Substrate Arithmetic for Safe Math
description:
Learn how math can be dangerous in the context of blockchain runtimes, and why floating point
numbers are not always accurate.
---

## Floating Point Numbers

## Negative Numbers

## Overflow Panic
## Integer Overflow

## Safe Math

Expand Down
15 changes: 11 additions & 4 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,17 @@ module.exports = {
"Rust/section2/data-types",
"Rust/section2/functions-comments",
"Rust/section2/loops",
"Rust/section2/alt-data-types",
"Rust/section2/common-traits",
"Rust/section2/casting-handling",
"Rust/section2/safe-math",
{
type: 'category',
link: { type: "doc", id: "Rust/section2/extended-index" },
label: 'Rust Basics Extended',
items: [
"Rust/section2/alt-data-types",
"Rust/section2/common-traits",
"Rust/section2/casting-handling",
"Rust/section2/safe-math",
],
},
],
},
{
Expand Down

0 comments on commit fb47642

Please sign in to comment.