From c032d12e35d58cc994a561cf68b58e6c0125fe27 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 23 Mar 2022 17:56:51 -0400 Subject: [PATCH] add space reference (#50) --- src/SUMMARY.md | 5 +- .../milestone_project_tic-tac-toe.md | 4 +- src/chapter_5/anchor_references.md | 2 + src/chapter_5/anchor_tooling.md | 2 - src/{ => chapter_5}/reference_links.md | 2 +- src/chapter_5/space.md | 50 +++++++++++++++++++ 6 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 src/chapter_5/anchor_references.md delete mode 100644 src/chapter_5/anchor_tooling.md rename src/{ => chapter_5}/reference_links.md (93%) create mode 100644 src/chapter_5/space.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ef6ea0c..65bef68 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -29,8 +29,9 @@ --- -- [Anchor Tooling](./chapter_5/anchor_tooling.md) +- [Anchor References](./chapter_5/anchor_references.md) + - [Space Reference](./chapter_5/space.md) - [CLI Reference](./chapter_5/cli.md) - [AVM Reference](./chapter_5/avm.md) - [Anchor.toml Reference](./chapter_5/anchor-toml_reference.md) -- [Reference Links](./reference_links.md) \ No newline at end of file + - [Code References](./chapter_5/reference_links.md) diff --git a/src/chapter_3/milestone_project_tic-tac-toe.md b/src/chapter_3/milestone_project_tic-tac-toe.md index eb522f6..68b62bd 100644 --- a/src/chapter_3/milestone_project_tic-tac-toe.md +++ b/src/chapter_3/milestone_project_tic-tac-toe.md @@ -247,7 +247,9 @@ Let us briefly explain how we arrived at the `Game::MAXIMUM_SIZE`. Anchor uses t - the `board` has a length of (`9 * (1 + 1)`). We know the board has 9 tiles (-> `9`) of type `Option` which borsh serializes with 1 byte (set to `1` for Some and `0` for None) plus the size of whatever's in the `Option`. In this case, it's a simple enum with types that don't hold more types so the maximum size of the enum is also just `1` (for its discriminant). In total that means we get `9 (tiles) * (1 (Option) + 1(Sign discriminant))`. - `state` is also an enum so we need `1` byte for the discriminant. We have to init the account with the maximum size and the maximum size of an enum is the size of its biggest variant. In this case that's the `winner` variant which holds a Pubkey. A Pubkey is `32` bytes long so the size of `state` is `1 (discriminant) + 32 (winner pubkey)` (`MAXIMUM_SIZE` is a [`const`](https://doc.rust-lang.org/std/keyword.const.html) variable so specifying it in terms of a sum of the sizes of `Game`'s members' fields does not incur any runtime cost). -In addition to the game's size, we have to add another 8 to the space. This is space for the internal discriminator which anchor sets automatically. In short, the discriminator is how anchor can differentiate between different accounts of the same program. +In addition to the game's size, we have to add another 8 to the space. This is space for the internal discriminator which anchor sets automatically. In short, the discriminator is how anchor can differentiate between different accounts of the same program. For more information, check out the Anchor space reference. + +> [Anchor Space Reference](./../chapter_5/space.md) > (What about using `mem::size_of()`? This almost works but not quite. The issue is that borsh will always serialize an option as 1 byte for the variant identifier and then additional x bytes for the content if it's Some. Rust uses null-pointer optimization to make Option's variant identifier 0 bytes when it can, so an option is sometimes just as big as its contents. This is the case with `Sign`. This means the `MAXIMUM_SIZE` could also be expressed as `mem::size_of() + 9`.) diff --git a/src/chapter_5/anchor_references.md b/src/chapter_5/anchor_references.md new file mode 100644 index 0000000..02a6b00 --- /dev/null +++ b/src/chapter_5/anchor_references.md @@ -0,0 +1,2 @@ +# Anchor References +Is exactly what it says on the tin. diff --git a/src/chapter_5/anchor_tooling.md b/src/chapter_5/anchor_tooling.md deleted file mode 100644 index 597960c..0000000 --- a/src/chapter_5/anchor_tooling.md +++ /dev/null @@ -1,2 +0,0 @@ -# Anchor Tooling -This chapter explores Anchor's tooling. diff --git a/src/reference_links.md b/src/chapter_5/reference_links.md similarity index 93% rename from src/reference_links.md rename to src/chapter_5/reference_links.md index 2525ee1..178a23a 100644 --- a/src/reference_links.md +++ b/src/chapter_5/reference_links.md @@ -1,4 +1,4 @@ -# Reference Links +# Code References - [Accounts Reference](https://docs.rs/anchor-lang/latest/anchor_lang/accounts/index.html) - [Constraints Reference](https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html) diff --git a/src/chapter_5/space.md b/src/chapter_5/space.md new file mode 100644 index 0000000..598e54c --- /dev/null +++ b/src/chapter_5/space.md @@ -0,0 +1,50 @@ +# Space Reference + +This reference tells you how much space you should allocate for an account. + +| Types | Space in bytes | Details/Example +| --------------- | -------------------- | ----------- +| bool | 1 | would only require 1 bit but still uses 1 byte +| u8/i8 | 1 | +| u16/i16 | 2 | +| u32/i32 | 4 | +| u64/i64 | 8 | +| u128/i128 | 16 | +| [T;amount] | space(T) * amount | e.g. space([u16;32]) = 2 * 32 = 64 +| Pubkey | 32 | +| Vec\ | 4 + (space(T) * amount) | Account size is fixed so account should be initialized with sufficient space from the beginning +| String | 4 + length of string in bytes | Account size is fixed so account should be initialized with sufficient space from the beginning +| Option | 1 + (space(T)) | +| Enum | 1 + Largest Variant Size | e.g. Enum { A, B { val: u8 }, C { val: u16 } } -> 1 + space(u16) = 3 +| f32 | 4 | serialization will fail for NaN +| f64 | 8 | serialization will fail for NaN + +# Example +```rust,ignore +#[account] +pub struct MyData { + pub val: u16, + pub state: GameState, + pub players: Vec // we want to support up to 10 players +} + +impl MyData { + pub const MAX_SIZE: usize = 2 + (1 + 32) + (4 + 10 * 32); +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq)] +pub enum GameState { + Active, + Tie, + Won { winner: Pubkey }, +} + +#[derive(Accounts)] +pub struct InitializeMyData<'info> { + // Note that we have to add 8 to the space for the internal anchor + #[account(init, payer = signer, space = 8 + MyData::MAX_SIZE)] + pub acc: Account<'info, MyData>, + pub signer: Signer<'info>, + pub system_program: Program<'info, System> +} +```