Accessing Private Data - demonoved/A-trial-run-in-solidity GitHub Wiki

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
//все данные на смарт контракте могут быть прочитаны
//Узнаем как же мы можем считывать данные, и разберемся с переменной хранения private
/* нельзя использовать web3 на JVM, поэтому разворачиваем на Goerli
0x534E4Ce0ffF779513793cfd70308AF195827BD31
*/
/*
хранение 
- 2 ** 256 слотов
- 32 байта для каждого слота - данные хранятся последовательно в порядке обьявления 
- хранение оптимизировано для экономии места, если соседние переменные помещаются в 32 байта, то они упаковываются в один слот начиная с правлого
*/
contract Vault {
    //slot 0
    uint public count = 123;
    //slot 1
    address public owner = msg.sender;
    bool public isTrue = true;
    uint16 public u16 = 31;
    //slot 2
    bytes32 private password;
    // константы не используют хранилище 
    uint public constant someConst = 123;
    // slot 3, 4, 5 ( по одному для каждого элемента массива)
    bytes32[3] public  data;
    struct User {
        uint id;
        bytes32 password;
    }
    //slot 6 - длина массива
    //начиная со слота hash(6) - элементы массива 
    // слот в котором хранится элемент массива = keccak256(slot) + (index * elementSize)
    // slot = 6 elementSize = 2(1(uint) + 1(bytes32))
    User[] private users;
    // slot 7 - пустой
    // записи хранятся в hash(key, slot)
    // где slot = 7, key = key mapping
    mapping(uint => User) private idToUser;
    constructor(bytes32 _password){
        password = _password;
    }
    function addUser(bytes32 _password) public {
        User memory user = User({id: users.length, password: _password});
        users.push(user);
        idToUser[user.id] = user;
    }
    function getArrayLocation(
        uint slot,
        uint index,
        uint elementSize
    )public pure returns(uint) {
        return uint( keccak256(abi.encodePacked(slot))) + (index * elementSize);
    }
    function getMapLocation(uint slot, uint key) public pure returns(uint){
        return uint(keccak256(abi.encodePacked(key, slot)));
    }
}

Давайте разберем каждую строку кода и объясним ее назначение:

  1. pragma solidity ^0.8.20;: Эта строка указывает версию компилятора Solidity, с которой совместим контракт.

  2. contract Vault { ... }: Здесь начинается объявление контракта "Vault".

  3. uint public count = 123;: Объявляется публичная переменная "count" типа "uint" (целое число без знака), которая инициализируется значением 123. Публичные переменные могут быть прочитаны извне контракта.

  4. address public owner = msg.sender;: Объявляется публичная переменная "owner" типа "address" (адрес Ethereum), которая инициализируется значением "msg.sender". "msg.sender" представляет адрес отправителя транзакции, которая вызвала эту функцию.

  5. bool public isTrue = true;: Объявляется публичная переменная "isTrue" типа "bool" (логическое значение), которая инициализируется значением "true".

  6. uint16 public u16 = 31;: Объявляется публичная переменная "u16" типа "uint16" (целое число без знака шириной 16 бит), которая инициализируется значением 31.

  7. bytes32 private password;: Объявляется приватная переменная "password" типа "bytes32" (динамический массив байтов длиной 32). Приватные переменные могут быть доступны только внутри контракта.

  8. uint public constant someConst = 123;: Объявляется публичная константа "someConst" типа "uint", которая инициализируется значением 123. Константы не используют хранилище и их значение не может быть изменено после инициализации.

  9. bytes32[3] public data;: Объявляется публичный статический массив "data" типа "bytes32" длиной 3. Этот массив может содержать 3 элемента типа "bytes32".

  10. struct User { ... }: Объявляется пользовательская структура "User", которая содержит два поля: "id" типа "uint" и "password" типа "bytes32".

  11. User[] private users;: Объявляется приватный динамический массив "users" типа "User", который будет хранить объекты типа "User".

  12. mapping(uint => User) private idToUser;: Объявляется приватное отображение (mapping) "idToUser", которое сопоставляет целочисленные ключи типа "uint" с объектами типа "User". Маппинг позволяет эффективно хранить и получать значения по ключу.

  13. constructor(bytes32 _password) { ... }: Это конструктор контракта, который принимает параметр "_password" типа "bytes32" и инициализирует приватную переменную "password" значением этого параметра.

  14. function addUser(bytes32 _password) public { ... }: Это публичная функция "addUser", которая принимает параметр "_password" типа "bytes32". Функция создает новый объект типа "User" с заданным паролем и добавляет его в массив "users" и отображение "idToUser".

  15. function getArrayLocation(uint slot, uint index, uint elementSize) public pure returns(uint) { ... }: Это публичная чистая (pure) функция "getArrayLocation", которая принимает параметры "slot", "index" и "elementSize" типа "uint" и возвращает значение типа "uint". Функция вычисляет местоположение элемента массива в хранилище на основе заданных параметров.

  16. function getMapLocation(uint slot, uint key) public pure returns(uint) { ... }: Это публичная чистая (pure) функция "getMapLocation", которая принимает параметры "slot" и "key" типа "uint" и возвращает значение типа "uint". Функция вычисляет местоположение записи в отображении (mapping) в хранилище на основе заданных параметров.

Это основные строки кода в предоставленном вами примере. Контракт "Vault" реализует хранение данных и демонстрирует использование различных типов переменных и структур данных в Solidity.