Solidity - почему метод получения по умолчанию общедоступной переменной Struct не возвращает каждую переменную внутри Struct

В настоящее время я изучаю язык Solidity и заметил, что когда я пытаюсь получить значение Struct внутри своего JS-кода, Solidity возвращает каждую переменную без массивов. Мне нужно создать собственный получатель для доступа ко всем данным внутри моей структуры.

Я сделал очень простой пример контракта со структурой, инициализированной внутри конструктора.

Я обращаюсь к переменной с помощью своего пользовательского получателя и сгенерировал ее внутри JS-кода.

Test.sol

      pragma solidity ^0.8.4;

contract Test {

    struct Data {
        string foo;
        address[] bar;
        address ctrt;
    }

    Data public d;

    constructor() {
        d.foo = "HELLO WORLD";
        d.bar.push(msg.sender);
        d.ctrt = address(this);
    }

    function getD() public view returns (Data memory) {
        return d;
    }
}

Test.js

      const {ethers} = require('hardhat');

describe('Test', function () {
  it('should test something', async function() {
    const factory = await ethers.getContractFactory('Test')
    const test = await factory.deploy();
    console.log("Result from var:");
    console.log(await test.d());
    console.log("Result from getter:");
    console.log(await test.getD());
  })
});

Результат в консоли:

      Result from var:
[
  'HELLO WORLD',
  '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  foo: 'HELLO WORLD',
  ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]
Result from getter:
[
  'HELLO WORLD',
  [ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
  '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  foo: 'HELLO WORLD',
  bar: [ '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' ],
  ctrt: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
]

Какой смысл явно говорить, что переменная является общедоступной, если какая-то часть данных не видна?

2 ответа

Автоматические геттеры, созданные для структур, возвращают все элементы структуры, кроме элементов, являющихся отображениями и массивами. Документы Solidity объясняют:

Сопоставление и массивы (за исключением массивов байтов) в структуре опущены, поскольку нет хорошего способа выбрать отдельные элементы структуры или указать ключ для сопоставления.

Итак, для вашего примера автоматически сгенерированный геттер выглядит так:

      function d() public returns (string foo, address ctrt) {
    foo = d.foo;
    ctrt = d.ctrt;
}

И, как и ожидалось, в вашем примере автоматически сгенерированный метод получения возвращает все элементы структуры, которые не являются отображениями или массивами, а ваш метод получения возвращает все элементы.

Цитата документов:

Если у вас есть общедоступная переменная состояния типа массива, вы можете получить только отдельные элементы массива с помощью сгенерированной функции получения. Этот механизм существует, чтобы избежать высоких затрат на газ при возврате всего массива.

Вот почему, когда вы выполняете вызов с помощью ethers.js, вы не видите этого значения.

Решение - создать getDataBar(uint i) функция, возвращающая содержимое бара.

Другие вопросы по тегам