Как просматривать структуры с помощью трюфеля

В моем контракте у меня есть такое отображениеmapping(uint => myStruct)

У меня есть checkфункция, в которой я даю, uint idи я хочу получить всю информацию в структуре (есть строки, адреса, uints,...) с помощью функции callв моем трюфеле app.js.

Как лучше всего это сделать? Могу ли я преобразовать каждое поле в строку и отправить массив строк? Должен ли я сделать отдельный геттер для каждого поля и использовать как можно больше callфункций?

Пока я просто возвращаю структуру и получаюinvalid solidity type!: tuple

Вы не можете вернуть структуру в твердом состоянии, по крайней мере, для текущей версии. поэтому вам нужно возвращать каждое значение отдельно. что-то вроде:return ( struct.member1,struct.member2)
Обратите внимание, что в Solidity ведется работа по поддержке сериализации сложных типов blog.ricmoo.com/…
@MedMansour Вы можете вернуть каждое значение отдельно за один возврат? Это меняет все, если js может с этим справиться!

Ответы (4)

Вам не нужна дополнительная функция Solidity, чтобы получить информацию из структуры. Вы можете вызвать структуру напрямую, используя web3.

Это помогает, если у вас есть функция в контракте для получения количества токенов, иначе вы можете застрять, используя while вместо for. Предположим, у вас есть функция, которая дает вам struct.length

var OwnableList = [];

//to get one struct entry you do this.

function getStructData(tokenId) {

    myContract.Ownables(tokenId, function(error, details) {
        if(details == undefined) {
            return false;
        } else {
            var name = details[0];
            var creator = details[1];
            var currentOwner = details[2];
            var isDestructible = details[3];
            var price = parseInt(details[4]);
            OwnableList.push({name: name, creator: creator, currentOwner: currentOwner, isDestructible: isDestructible, price: price});
    })
    return true;
    }
}

//to get all struct entrys you do this

function dumpStructData() {
    myContract.totalOwnables(function(error, total) {
        for(i=0; i<parseInt(total); i++) {
            getStructData(i);
        }
    }
}

//now you can just read the struct

function showStruct() {
    console.log(JSON.stringify(OwnableList);
}

Видимо мой вопрос был неправильно понят, но я решил проблему с помощью Mikko Ohtamaa в комментариях.

По какой-то причине я не понял, что могу вернуть несколько переменных (и разных типов!). Если вы знаете, что можете это сделать, на самом деле нет проблем. Javascript справляется с этим очень хорошо.

Мое решение выглядит примерно так:

contract myContract {
  struct Ownable {
    string name;
    address creator;
    address currentOwner;
    bool isDestructible;
    uint price;
  }

  mapping (uint => Ownable) public Ownables;

  function getOwnableInfo(uint OwnableId) public view returns (string, address, address, bool, uint){
    Ownable o = Ownables[OwnableId];
    return (o.name, o.creator, o.currentOwner, o.isDestructible, o.price);
  }

  /.../
}

И в соответствующем трюфеле callвернет массив с переменными возврата по порядку:

myContractInstance.getOwnableInfo.call(ownableId).then((resultArray => {
  name = resultArray[0];
  creator = resultArray[1];
  currentOwner = resultArray[2];
  /.../
});

Примечания:

  • Не заглядывайте слишком много в Ownable o = Ownables[OwnableId];, я сделал это, чтобы улучшить читаемость, я не думаю, что это полезно или вообще хорошо.
  • Если одно из данных представляет собой большое число (обычно это цена Wei), я преобразую его с помощью bignumber, resultArray[4].toNumber()чтобы JavaScript мог его обработать.

лучший способ добавить что-то в структуру и получить все записи:

pragma solidity ^0.4.17;

contract test {
    struct Record {
        string name;
        string homeAddress;
    }

    Record[] public records;

    function AddRecord(string Address , string Name) public {
        Record memory newRec = Record({
            name : Name,
            homeAddress : Address
        });

        records.push(newRec);
    }

    function recordsArrayLength() public view returns(uint256){
        return records.length;
    }

}

и в вашем пользовательском интерфейсе используйте этот код:

сначала используйте let len = await test.methods.recordsArrayLength().call()и получите lengthмассив записей, а затем нажмите этот код:

let records = []

for(let i=0;i<len;i++){
    records.push(await test.methods.records(i))
}

и теперь у вас есть вся структура

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

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

mapping(bytes32 => RecordStruct) public recordStructs;
bytes32 public recordKeys;

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

Существуют ли хорошо решенные и простые шаблоны хранения для Solidity?

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

Надеюсь, поможет.

Что вы имеете в виду под « не зная, в какой строке он находится »? Ваш ответ выглядит интересно, но я не уверен, чего вы пытаетесь достичь.
У вас mapping(uint => myStruct)есть структуры, хранящиеся по номеру, и вопрос касается перехода к массиву (также по номеру). Я хочу получить по ключу (например, "ORD002" или "0x123...") и не хочу искать. Я также хочу список и количество.
Я думаю, вы неправильно поняли мой вопрос. Я не хочу мигрировать, у меня есть структура с несколькими данными разных типов, и я хочу написать функцию с callтрюфелем, чтобы получить всю эту информацию.
Я написал ответ о том, как я решил свою проблему, может быть, вы лучше поймете, что я имел в виду.