Этот вопрос был задан здесь, но я подумал, что сделаю это немного яснее. Можно ли получить доступ к 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
он не инициализирован в хранилище?
Если вы можете простить саморекламу, этот объяснитель может показать способ достижения цели: 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
, чтобы узнать, обновляете ли вы или вставляете.
Надеюсь, поможет.
Вы не можете получить список пар ключ-> значение сопоставления внутри структуры по той же причине, по которой вы не можете получить пары ключ-значение сопоставления вне структуры: контракт не знает, что это такое. . См. этот ответ для более подробного объяснения: можем ли мы получить все элементы, хранящиеся в отображении в контракте?
Предполагая, что у вас есть ключи, вы можете создать свой собственный метод доступа для его извлечения, например, что-то вроде:
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
. Если вы хотите сказать «просто дайте мне все пары ключ/значение этого сопоставления», то Solidity не сможет вам помочь. Вы должны либо передать ключ в функцию доступа, либо сохранить его (или информацию, которую вам нужно знать, что это такое, например, последний индекс списка, который вы назначаете последовательно) в другом месте вашего контракта.
Исмаэль
Роб Хитченс
УВД
Роб Хитченс
УВД