Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the concept of block chain ethernet storage type and variable storage

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)05/31 Report--

Today, the editor will share with you the relevant knowledge of what the block chain ethernet storage type and variable storage concept is. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge. So share this article for your reference. I hope you can get something after reading this article. Let's take a look at it.

Data storage location (Data location) concept

1.1 distinction between storage, memory, calldata and stack

In Solidity, there are two places to store variables: storage (storage) and memory (memory). Storage variables are variables that are permanently stored in the blockchain. The Memory variable is temporary, and when the external function is called on a contract, the memory variable is removed.

The memory (memory) location also contains two types of storage data locations, one is calldata, and the other is stack.

(1) calldata

This is a read-only location that is not permanently stored to store function parameters. The data location of the parameters (non-return parameters) of the external function is forced to be specified as calldata, which is similar to memory.

(2) Stack (stack)

In addition, EVM is a stack-based language, the stack is actually a data structure in memory, each stack element occupies 256bits, and the maximum length of the stack is 1024. Local variables of value types are stored on the stack.

The consumption (gas consumption) varies with different storage, which is explained as follows:

Storage keeps the contract status variable permanently, which is the most expensive.

Memory saves only temporary variables, which is released after the function call, and the overhead is very small.

Stack holds very small local variables, free to use, but limited in number (16 variables)

The data of calldata contains the data of the message body, and its calculation requires an increase in the GAS cost of Nation68.

The storage storage structure is determined when the contract is created, depending on the state variables declared by the contract. But the content can be changed by the call.

Solidity calls this a state change, which is why contract-level variables are called state variables. You can also better understand why state variables are stored in storage.

Memory can only be used inside a function, and the memory declaration is used to tell EVM to create a (fixed size) memory area for use by variables at run time.

Storage is stored as key/value in the chunk chain, while memory is represented as a byte array

1.2 extended reading of stack (stack)

EVM is a virtual machine based on stack. This means that stacks instead of registers are used for most operations. Stack-based machines tend to be simple and easy to optimize, but their disadvantage is that they require more opcode than register-based machines.

So EVM has a lot of unique operations, most of which are only used on the stack. For example, SWAP and DUP series operations, see the EVM documentation for details. Now let's try to compile the following contract:

Pragma solidity ^ 0.4.13 X contract Something {function foo (address a1, address a2, address a3, address a4, address a5, address a6) {address a7; address a8; address a9; address a10; address a11; address a12; address a13; address a14; address a15; address a16; address a17;}}

You will see the following error:

CompilerError: Stack too deep, try removing local variables.

This error is due to an overflow when the stack depth exceeds 16:00. The official "solution" is to advise developers to reduce the use of variables and keep functions as small as possible. Of course, there are several other workarounds, such as wrapping variables in struct or arrays, or using the keyword memory (for some reason, it can't be used for ordinary variables). In that case, let's try this solution using struct:

Pragma solidity ^ 0.4.13 X contract Something {struct meh {address x;} function foo (address A1, address a2, address a3, address a4, address a5, address a6) {address A7; address a8; address A9; address a10; address a11; address a12; address a13; meh memory a14; meh memory a15; meh memory a16; meh memory a17 }}

How did it turn out?

CompilerError: Stack too deep, try removing local variables.

Why do we still have a problem when we use the memory keyword? The point is that although we didn't store 17 256bit integers on the stack this time, we tried to store 13 integers and 4 256bit memory addresses.

This includes some problems with Solidity itself, but the main problem is that EVM cannot have random access to the stack. As far as I know, other virtual machines often solve this problem in one of two ways:

Smaller stack depths are encouraged, but stack elements can be easily exchanged with memory or other storage (such as local variables in .NET)

Implement pick or similar instructions for random access to stack elements

However, in EVM, the stack is the only free area to store data, and other areas need to pay gas. Therefore, this is tantamount to encouraging the use of stacks as much as possible, as fees are charged in other areas. Because of this, we encounter the basic language implementation problems described above.

Storage locations for different data types

Solidity types are divided into two types: value types (Value Type) and reference types (Reference Types). Solidity provides several basic types that can be used to combine complex types.

(1) value type (Value Type) means that a variable always makes a copy of the value when assigning or passing parameters, including:

Boolean type (Booleans)

Integer (Integers)

Fixed length floating point (Fixed Point Numbers)

Fixed length byte array (Fixed-size byte arrays)

Rational numbers and integer constants (Rational and Integer Literals)

String constant (String literals)

Hexadecimal constant (Hexadecimal literals)

Enumeration (Enums)

Function (Function Types)

Address (Address)

Address constant (Address Literals)

(2) reference type (Reference Types)

It means that when assigning a value, we can pass either value or reference, that is, address, including:

Variable length byte array (bytes)

String (string)

Array (Array)

Structure (Struts)

A reference type is a complex type that usually takes up more than 256 bits of space and is expensive to copy.

All complex types, namely array and structure types, have an additional attribute: "data location", which indicates whether the data is stored in memory (memory, the data is not permanent) or stored (storage, permanently stored in the blockchain). Data has a default location most of the time, depending on the context, but it can also be modified by adding a keyword (storage) or (memory) to the type name.

The default storage location for variables is:

Function parameters (including returned parameters) default to memory

Local variable (local variables) defaults to storage

The state variable (state variables) defaults to storage

Local variable: a variable with a local scope (beyond the scope that is inaccessible, waiting to be recycled), such as a variable within a function. State variables: public variables declared in the contract

Data location assignments are important because they affect assignment behavior.

Assigning values to each other between memory and storage or with state variables always creates a completely independent copy.

And assigning a state variable of storage to a local variable of storage is passed by reference. So for the modification of the local variable, modify the associated state variable at the same time.

On the other hand, assigning a reference type of one memory to a reference of another memory does not create a copy (that is, reference passing between memory).

Note: memory cannot be assigned to local variables. For value types, it is always copied.

The following is an illustration of the contract code:

Pragma solidity ^ 0.4.0X contract C {uint [] x; / x data storage location is storage / / memoryArray data storage location is memory function f (uint [] memoryArray) public {x = memoryArray; / / copy the entire array into storage, feasible var y = x; / / assign a pointer (where y's data storage location is storage), feasible y [7] / / return the eighth element, feasible y.length = 2; / / modify x through y, feasible delete x; / / clear the array, while modifying y, feasible / / the following is not feasible You need to create a new unnamed temporary array in storage, but storage is "statically" allocated: / / y = memoryArray; / / the following line is not feasible either, because it "resets" the pointer, / / but there is no appropriate storage location for it to point to. / / delete y; g (x); / / call g function while handing over the reference to x h (x); / / call h function and create an independent temporary copy} function g (uint [] storage storageArray) internal {} function h (uint [] memoryArray) public {} variable in memory

3.1 locate the value of a fixed size

How on earth is it stored in this storage model? For known variables that have a fixed size, it is reasonable to give them reserved space in memory. This is what the Solidity programming language does.

Contract StorageTest {uint256 a; uint256 [2] b; struct Entry {uint256 id; uint256 value;} Entry c;}

In the above code:

An is stored at subscript 0. (the term solidity refers to the location of storage in memory is "slot". )

B is stored in subscript 1 and 2 (one for each element of the array).

C starts at slot 3 and consumes two slots because the structure Entry stores two 32-byte values.

These subscript locations are determined at compile time and are based strictly on the order in which variables appear in the contract code.

3.2 find the value of the dynamic size

The method of preserving subscripts is suitable for storing fixed-size state variables, but not for dynamic arrays and mappings (mapping), because there is no way to know how many slots need to be preserved.

If you want to use a computer RAM or hard drive as a metaphor, you may want to have an "allocate" step to find free space, and then perform the "release" step to put that space back into the available storage pool.

But this is unnecessary because smart contract storage is an astronomical scale. There are 2 ^ 256 locations in the memory to choose from, which is about the number of atoms in the known observable universe. You can choose the storage location at will without collisions. The locations you choose are so far apart that you can store as much data as possible in each location without having to move on to the next location.

Of course, choosing a location at random won't be very helpful because you can't find the data again. Solidity instead uses hash functions to unify and repeatedly calculate the location of dynamic size values.

3.3 an array of dynamic sizes

A dynamic array needs a place to store its size and its elements.

Contract StorageTest {uint256 a; / / slot 0 uint256 [2] b; / slots 1-2 struct Entry {uint256 id; uint256 value;} Entry c; / / slots 3-4 Entry [] d;}

In the above code, the dynamically sized array d has the location of subscript 5, but the only data stored is the size of the array. The values in the array d are stored continuously from the hash value hash (5) of the subscript.

The following Solidity function calculates the location of dynamic array elements:

Function arrLocation (uint256 slot, uint256 index, uint256 elementSize) public pure returns (uint256) {return uint256 (keccak256 (slot)) + (index * elementSize);}

3.4 Mapping (Mappings)

A mapping mapping requires an efficient way to find the location corresponding to a given key. Calculating the hash of a key is a good start, but care must be taken to make sure that different mappings results in different locations.

Contract StorageTest {uint256 a; / slot 0 uint256 [2] b; / slots 1-2 struct Entry {uint256 id; uint256 value;} Entry c; / / slots 3-4 Entry [] d; / / slot 5 for length, keccak256 (5) + for data mapping (uint256 = > uint256) e; mapping (uint256 = > uint256) f;}

In the above code, the "position" of e is subscript 6 and the location of f is subscript 7, but there is actually nothing stored in these locations. (I don't know how long it needs to be stored, and independent values need to be located elsewhere. )

To find the location of a specific value in the mapping, the key and the subscript stored in the mapping are hashed together.

The following Solidity function calculates the location of the value:

Function mapLocation (uint256 slot, uint256 key) public pure returns (uint256) {return uint256 (keccak256 (key, slot));}

Note that when the keccak256 function has more than one parameter, concatenate the parameters before hashing. Because the subscript and key are inputs to the hash function, there is no conflict between different mappings.

3.5 combinations of complex types

Dynamic size arrays and mappings can be recursively nested together. When this happens, the location of the value is found by recursively applying the calculation defined above. It sounds more complicated than it is.

Contract StorageTest {uint256 a; / slot 0 uint256 [2] b; / slots 1-2 struct Entry {uint256 id; uint256 value;} Entry c; / slots 3-4 Entry [] d; / / slot 5 for length, keccak256 (5) + for data mapping (uint256 = > uint256) e; / / slot 6, data at h (k. 6) mapping (uint256 = > uint256) f; / / slot 7, data at h (k. 7) mapping (uint256 = > uint256 []) g; / / slot 8 mapping (uint256 = > uint256) [] h; / / slot 9}

To find the items in these complex types, we can use the functions defined above. To find g123:

/ / first find arr = g [123] arrLoc = mapLocation (8,123); / / g is at slot 8 then find arr / then find arr [0] itemLoc = arrLocation (arrLoc, 0,1)

To find H3:

/ / first find map = h [2] mapLoc = arrLocation (9,2,1); / / h is at slot 9 then find map / then find map itemLoc = mapLocation (mapLoc, 456)

3.6 Summary

Each smart contract is stored as an array of 2 ^ 256 32-byte values, all initialized to zero.

Zero has no explicit storage, so setting the value to zero reclaims the storage.

In Solidity, the value that determines the memory size starts with the No. 0 subscript.

Solidity makes use of the sparsity of storage and the uniform distribution of hash output to safely locate the value of dynamic size.

The following table shows how to calculate different types of storage locations. "subscript" refers to the next available subscript when a state variable is encountered at compile time, and a dot represents binary concatenation:

These are all the contents of this article entitled "what is the concept of block chain ethernet storage type and variable storage". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report