From df617070aecd3033b689a78556bcc1e1cfe13259 Mon Sep 17 00:00:00 2001 From: 0xfps Date: Thu, 16 May 2024 16:28:33 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=204-2=20done.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../4-2-1-uint8-uint128-uint256.md | 5 +- .../4-2-10-custom-types.md | 40 +++++++++++ .../4-2-11-uint8[]-uint128[]-uint256[].md | 70 +++++++++++++++++++ .../4-2-12-int8[]-int128[]-int256[].md | 3 + .../4-2-13-bytes1[]-bytes16[]-bytes32[].md | 3 + .../4-2-14-bytes[].md | 3 + .../4-2-15-string[].md | 3 + .../4-2-16-address[].md | 3 + .../4-2-17-custom-types[].md | 3 + book/src/SUMMARY.md | 10 ++- 10 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8[]-uint128[]-uint256[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8[]-int128[]-int256[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1[]-bytes16[]-bytes32[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address[].md create mode 100644 book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types[].md diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-1-uint8-uint128-uint256.md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-1-uint8-uint128-uint256.md index 86dd25a..821b797 100644 --- a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-1-uint8-uint128-uint256.md +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-1-uint8-uint128-uint256.md @@ -1,9 +1,10 @@ # `uint8`, `uint128`, `uint256` -Unsigned integers are stored in memory based on the size of bytes they have. While sm all uint values like uint8 have 1 byte, uint256 has 32 bytes. Solidity's storage is designed in such a way that it can contain up to 32 bytes of value in one slot. In a situation where a variable doesn't contain up to 32 bytes, the value is stored and the next variable will be **packed** into the same slot, on the condition that when the bytes are added to the slot, it doesn't exceed 32 bytes. +Unsigned integers are stored in memory based on the size of bytes they have. The size of `uint[n]` bytes can be realized by dividing `[n]` by 8, meaning that, while small `uint[n]` values like `uint8` have 1 byte, `uint256` has 32 bytes. Solidity's storage is designed in such a way that it can contain up to 32 bytes of value in one slot. In a situation where a variable doesn't contain up to 32 bytes, the value is stored and the next variable will be **packed** into the same slot, on the condition that when the bytes are added to the slot, it doesn't exceed 32 bytes. -`uint256` => 32 bytes => Slot 0.
+`uint256` => 32 bytes => Slot 0. + This is the maximum, hence it occupies an entire slot of its own. Whatever bytes we are going to add will exceed 32 and hence, will pick up the next slot, slot 1. `uint128` => 16 bytes => Slot 1. We still have 16 bytes left to be filled.
diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md new file mode 100644 index 0000000..3bca8f8 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md @@ -0,0 +1,40 @@ +# Custom Types + +A custom type or a user-defined value type allows you to create an alias of a native type in Solidity. This alias, will inherit and act as if it is the original type. It is defined by using the `type C is V syntax`, where `C` is the custom type, and `V` is the native type. To convert from the underlying type to the custom type, `C.wrap()` is used, and to convert from the custom type to the native underlying type, `C.unwrap()` is used [[6](https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types)]. + +Custom types behave like their underlying types. + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +contract Yul { + type CustomTypeUint8 is uint8; // Will behave like uint8. + type CustomTypeUint256 is uint256; // Will behave like uint256. + type CustomTypeInt128 is int128; // Will behave like int128. + type CustomTypeAddress is address; // Will behave like address. + type CustomTypeBytes4 is bytes4; // Will behave like bytes4. + type CustomTypeBytes32 is bytes32; // Will behave like bytes32. + + // Slot 0. + CustomTypeUint256 public customType = CustomTypeUint256.wrap(12000); + // Slot 1. + uint256 public underlyingType = CustomTypeUint256.unwrap(customType); + + function getCustomType() public view returns (bytes32) { + assembly { + mstore(0x80, sload(0x00)) + return(0x80, 0x20) + } + } + + function getUnderlyingType() public view returns (bytes32) { + assembly { + mstore(0x80, sload(0x01)) + return(0x80, 0x20) + } + } +} +``` + +> 🚨 You cannot define custom types for `bytes` and `string`. \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8[]-uint128[]-uint256[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8[]-uint128[]-uint256[].md new file mode 100644 index 0000000..219cedf --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8[]-uint128[]-uint256[].md @@ -0,0 +1,70 @@ +# `uint8[]`, `uint128[]`, `uint256[]` + +Up till now, we've learnt about individual data types in Solidity and how they are stored in storage. Before we proceed to their array counterparts, we would want to go over how arrays are viewed in Solidity storage generally. This view is applied to all other types. + +Solidity recognizes two types of arrays, the fixed length array and the dynamic array. These two array types are +treated differently by Solidity. + +## Fixed Arrays, `[n]` + +Solidity views `[n]` array elements as individual values. Which means that, these values are treated as if they +were +not in an array. If a `uint256[5]` array has 5 elements, they will occupy 5 slots, in their correct places. + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +contract Yul { + // Slots 0 - 4. + uint256[5] public fixedArray; + // Slot 5. + uint8[6] public fixedSmallArray; +} +``` +In the code above, the `fixedArray` variable occupies 5 slots. This is because, it contains 5 `uint256` values. In +Solidity, because the length of the array is fixed (in this case, 5), Solidity knows how much in storage to allocate +for the storage of each individual value. It is seen as if they're 5 `uint256` values kept side by side. + +The `fixedSmallArray` occupies one slot, because, as explained, it will be seen as 6 `uint8` values kept side by +side and they, like we have already discussed, will be packed into one slot. + +## Dynamic Arrays, `[]` + +Dynamic arrays are stored just like fixed arrays, when it comes to packing, but in terms of knowing **where** in +storage to store the array, a little bit of calculation is done. Because the length is dynamic, Solidity does not +know how much space to allocate for the storage, therefore, the storage of a dynamic array starts at `keccak256(slot) +`. Meaning that, if a dynamic array is declared at slot 0, the first element will be found `keccak256(0)`. + +To read the value of the other array elements from storage, they will be obtained by loading the storage at +`keccak256(slot) + elementIndex`. Meaning that, if we had the above dynamic array that grew to 10 elements, and we +would +like to retrieve the value of the 9th element, it would be found at `keccak256(0) + 9`. + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +contract Yul { + // Slot 0. + uint256[] public dynamicArray; + // Slot 1. + uint8[] public dynamicSmallArray; +} +``` + +The values of the elements in the dynamicArray variable can be found at `keccak256(0) + elementIndex`. While the +values for the `dynamicSmallArray` will be found at `keccak256(1)`, we didn't add any `elementIndex` here because +the elements of `dynamicSmallArray` will be packed in one slot because they're `uint8` and will be packed. If they are +more than enough to fit into the next slot, then, we can load the next storage location. + +## General `[]` Deduction. + +Once the concept of type storages is understood, you can use that to figure out how the array versions of that type +will be stored. + +You can use the knowledge of arrays to write to any array index, or read from an array index. + +To retrieve an element from a packed array is quite trick and is not readily advised. + +> 🚨 The use of Yul to read and write arrays is not advised. It is a very tricky business. \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8[]-int128[]-int256[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8[]-int128[]-int256[].md new file mode 100644 index 0000000..85f3776 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8[]-int128[]-int256[].md @@ -0,0 +1,3 @@ +# `int8[]`, `int128[]`, `int256[]` + +Combine the knowledge of [int8, int128 and int256](4-2-2-int8-int128-int256.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1[]-bytes16[]-bytes32[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1[]-bytes16[]-bytes32[].md new file mode 100644 index 0000000..b8bf212 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1[]-bytes16[]-bytes32[].md @@ -0,0 +1,3 @@ +# `bytes1[]`, `bytes16[]`, `bytes32[]` + +Combine the knowledge of [bytes1, bytes16, bytes32](4-2-3-bytes1-bytes16-bytes32.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes[].md new file mode 100644 index 0000000..c58a992 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes[].md @@ -0,0 +1,3 @@ +# `bytes[]` + +Combine the knowledge of [bytes](4-2-4-bytes.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string[].md new file mode 100644 index 0000000..accd1ab --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string[].md @@ -0,0 +1,3 @@ +# `string[]` + +Combine the knowledge of [string](4-2-5-string.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address[].md new file mode 100644 index 0000000..4c57760 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address[].md @@ -0,0 +1,3 @@ +# `address[]` + +Combine the knowledge of [address](4-2-6-address.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types[].md b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types[].md new file mode 100644 index 0000000..e89af18 --- /dev/null +++ b/book/src/4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types[].md @@ -0,0 +1,3 @@ +# `Custom Types[]` + +Combine the knowledge of [Custom Types](4-2-10-custom-types.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md). \ No newline at end of file diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 6fdf91b..3cdff15 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -35,4 +35,12 @@ - [address](4-yul-implementations/4-2-variable-storage-in-storage/4-2-6-address.md) - [struct](4-yul-implementations/4-2-variable-storage-in-storage/4-2-7-struct.md) - [mapping](4-yul-implementations/4-2-variable-storage-in-storage/4-2-8-mapping.md) - - [enum](4-yul-implementations/4-2-variable-storage-in-storage/4-2-9-enum.md) \ No newline at end of file + - [enum](4-yul-implementations/4-2-variable-storage-in-storage/4-2-9-enum.md) + - [Custom Types](4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md) + - [uint8[], uint128[], uint256[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md) + - [int8[], int128[], int256[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8%5B%5D-int128%5B%5D-int256%5B%5D.md) + - [bytes1[], bytes16[], bytes32[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1%5B%5D-bytes16%5B%5D-bytes32%5B%5D.md) + - [bytes[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes%5B%5D.md) + - [string[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string%5B%5D.md) + - [address[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address%5B%5D.md) + - [Custom Types[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types%5B%5D.md) \ No newline at end of file