Доступ к сопоставлению внутри структуры через консоль Truffle

Этот вопрос был задан здесь, но я подумал, что сделаю это немного яснее. Можно ли получить доступ к fundersсопоставлению (выделено жирным шрифтом) через консоль Truffle в приведенном ниже коде? Это взято из документации Solidity :

struct Funder {
    address addr;
    uint amount;
}

struct Campaign {
    address beneficiary;
    uint fundingGoal;
    uint numFunders;
    uint amount;
    mapping (uint => Funder) funders;
}

uint numCampaigns;
mapping (uint => Campaign) campaigns;

function newCampaign(address beneficiary, uint goal) returns (uint campaignID) {
    campaignID = numCampaigns++; // campaignID is return variable
    // Creates new struct and saves in storage. We leave out the mapping type.
    campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
}

function contribute(uint campaignID) payable {
    Campaign storage c = campaigns[campaignID];
    // Creates a new temporary memory struct, initialised with the given values
    // and copies it over to storage.
    // Note that you can also use Funder(msg.sender, msg.value) to initialise.
    c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value});
    c.amount += msg.value;
}

После запуска newCampaignи contributeдобавления средств во вновь созданную кампанию объект, возвращенный обратно, выглядит следующим образом:

[ '0x740bd112e4d310a69aae3cee9ca8e72d1b1f8a21', { [String: '15000'] s: 1, e: 4, c: [ 15000 ] }, { [String: '5'] s: 1, e: 0, c: [ 5 ] }, { [String: '16000'] s: 1, e: 4, c: [ 16000 ] }, { [String: '1504125631'] s: 1, e: 9, c: [ 1504125631 ] } ]

Все переменные в Campaignструктуре видны, кроме самой fundersпеременной. Возможно , это потому, что fundersон не инициализирован в хранилище?

Ответы (2)

Если вы можете простить саморекламу, этот объяснитель может показать способ достижения цели: https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42 .

РЕДАКТИРОВАТЬ

Основная идея заключается в следующем.

Базовая структура данных для обеих сущностей — это сопоставление структур (для произвольного доступа) и неупорядоченный индекс ключей в виде динамического массива (для облегчения подсчета и перечисления). Здесь есть пример под заголовком «Отображенная структура с индексом». Существуют ли хорошо решенные и простые шаблоны хранения для Solidity?

Таким образом, вы просто создаете контракт с двумя из них для своих двух объектов.

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

Грубо:

struct CampaignStruct {
  ...
  address funders[];
  bool exists;
}

mapping(bytes32 => CampaignStruct) public campaignStructs;
bytes32[] public campaignIndex;

struct FunderStruct {
  ...
  bool exists;
}

mapping(address => FunderStruct) public funderStructs;
address[] public funderIndex;

function getCampaignCount() public constant returns(uint count) {
   return campaignIndex.length;
}

function getFunderCount() public constant returns(uint count) {
   return funderIndex.length;
}

function getCampaignAtIndex(uint row) public constant returns(<details>) {}

function getCampaignFunderCount(bytes32 campaignId) public constant returns(uint count) {
   return campaignStructs[campaignId].funders.length;
}

function getCampaignFunderAtIndex(bytes32 campaignId, uint row) public constant returns(address funder)

{
   return campaignStructs[campaignId].funders[row];
}

Если вам не нужно удалять, средство записи в стиле upsert сделает свое дело, потому что вы можете писать непосредственно в сопоставление. Новые ключи добавляются в индексы с помощью .push(). Вы можете использовать a bool exists, чтобы узнать, обновляете ли вы или вставляете.

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

Подобный ответ не очень полезен, если ссылки исчезнут, он закончится без содержания. Лучше, если вы поместите здесь основную мысль, а ссылки будут служить дополнением.
Дело принято. Я добавил очень сжатый, который, надеюсь, связный.
@RobHitchens Я все еще не понимаю, как получить доступ к отображению внутри структуры, учитывая код, опубликованный в моем вопросе. Эдмунд предложил создать собственную функцию доступа.
Дело в том, что ты не можешь. Вот почему я предлагаю отказаться от сопоставления, к которому у вас нет доступа, и использовать массив, к которому у вас есть доступ. Для ясности (надеюсь) вы могли бы создать функцию, которая возвращает одно отображаемое значение за раз, но вам нужно будет предоставить ключ для сопоставления, чтобы знать, какое «одно» вернуть. Это означает, что вам нужно где-то хранить список. Вся идея наброска кода выше состоит в том, чтобы сохранить список вместо использования структуры данных, которая не будет делать то, что вы хотите.
Попался. Я просто пытаюсь работать в контексте документов Solidity.

Вы не можете получить список пар ключ-> значение сопоставления внутри структуры по той же причине, по которой вы не можете получить пары ключ-значение сопоставления вне структуры: контракт не знает, что это такое. . См. этот ответ для более подробного объяснения: можем ли мы получить все элементы, хранящиеся в отображении в контракте?

Предполагая, что у вас есть ключи, вы можете создать свой собственный метод доступа для его извлечения, например, что-то вроде:

function campaign_funder(uint campaignID, uint funderID) constant returns (address) {
    return campaigns[campaignID].funders[funderID].addr;
}

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

Вы не можете получить список пар ключ->значение сопоставления внутри структуры по той же причине, по которой вы не можете получить пары ключ-значение сопоставления вне структуры . Я не верю, что это правда согласно документам . Если вы сделаете campaignsтип общедоступным, чтобы он читался, mapping (uint => Campaign) public campaigns;вы можете получить доступ к сопоставлению, просто выполнив campaigns[0], чтобы получить первую пару ключ-> значение. Вот как я смог получить результат в вопросе. Функция доступа, кажется, путь.
Я также попытался скомпилировать campaign_funderопределенную вами функцию, и она выдает ошибку «Ссылка на хранилище фонда не может быть неявно преобразована в адрес ожидаемого типа (типа первой возвращаемой переменной)». Функция пытается вернуть структуру, что невозможно в Solidity.
Извините, да, спонсоры - campaigns[campaignID].fundersэто структуры Funder, а не адреса, поэтому (тоже не проверено)return campaigns[campaignID].funders[funderID].addr;
«вы можете получить доступ к сопоставлению, просто выполнив кампании [0], чтобы получить первую пару ключ-> значение». : это работает, потому что вы предоставляете ключ сопоставления, то есть 0. Если вы хотите сказать «просто дайте мне все пары ключ/значение этого сопоставления», то Solidity не сможет вам помочь. Вы должны либо передать ключ в функцию доступа, либо сохранить его (или информацию, которую вам нужно знать, что это такое, например, последний индекс списка, который вы назначаете последовательно) в другом месте вашего контракта.
Да, это имеет смысл.