Я храню данные в своем контракте, используя сопоставление структур.
Для примера предположим, что я храню информацию о сотрудниках (имя/адрес/зарплата), сопоставленную с их идентификатором сотрудника.
Через веб-интерфейс я хотел бы указать идентификатор сотрудника и вызвать функцию в моем контракте (используя Web3.JS), которая возвращает информацию о сотруднике.
Как я могу получить доступ к данным, если возвращается структура. Это возможно?
Возвращайте поля структуры как отдельные возвращаемые переменные.
Изменить: с 2021 года можно напрямую вернуть структуру. Смотрите этот ответ .
Я запускаю этот код в своем локальном блокчейне разработки, используя следующую команду:
geth --datadir ~/devdata --dev --nodiscover \
--mine --minerthreads 1 --port 30301 \
--maxpeers 0 --verbosity 3 --rpc console
Ваш веб-интерфейс должен иметь возможность отправлять транзакции для вставки пользователей и вызывать функции для получения количества пользователей и информации о пользователе.
contract SalaryInfo {
struct User {
uint salaryId;
string name;
string userAddress;
uint salary;
}
User[] public users;
function addUser(uint _salaryId, string _name, string _userAddress, uint _salary) public returns(uint) {
users.length++;
users[users.length-1].salaryId = _salaryId;
users[users.length-1].name = _name;
users[users.length-1].userAddress = _userAddress;
users[users.length-1].salary = _salary;
return users.length;
}
function getUsersCount() public constant returns(uint) {
return users.length;
}
function getUser(uint index) public constant returns(uint, string, string, uint) {
return (users[index].salaryId, users[index].name, users[index].userAddress, users[index].salary);
}
}
Я использую stripCrLf
метод (из Как загрузить исходный файл Solidity в geth ) для преобразования отформатированного исходного кода в одну строку, которую можно вставить в geth
консоль. В качестве альтернативы найдите веб-страницу, которая удалит разрывы строк из вашего кода. Затем назначьте свой код переменной JavaScript:
> var salaryInfoSource='contract SalaryInfo { struct User { uint salaryId; string name; string userAddress; uint salary; } User[] public users; function addUser(uint _salaryId, string _name, string _userAddress, uint _salary) public returns(uint) { users.length++; users[users.length-1].salaryId = _salaryId; users[users.length-1].name = _name; users[users.length-1].userAddress = _userAddress; users[users.length-1].salary = _salary; return users.length; } function getUsersCount() public constant returns(uint) { return users.length; } function getUser(uint index) public constant returns(uint, string, string, uint) { return (users[index].salaryId, users[index].name, users[index].userAddress, users[index].salary); }}'
Скомпилировать код:
> var salaryInfoCompiled = web3.eth.compile.solidity(salaryInfoSource);
Загрузите код в блокчейн:
> var salaryInfoContract = web3.eth.contract(salaryInfoCompiled.SalaryInfo.info.abiDefinition);
> var salaryInfo = salaryInfoContract.new({from:web3.eth.accounts[0], data: salaryInfoCompiled.SalaryInfo.code, gas: 1000000},
function(e, contract) {
if (!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " +
contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
}
)
Подождите, пока не появится следующее сообщение о том, что контракт был добыт:
I0505 09:12:15.712867 27030 xeth.go:1026] Tx(0x7747500b881c8da44efbc3b5d1c2c762f1cd52d2dd74050edbfed10e51a29d8a) created: 0x0bb1d7a6b31f7a7e23e6d902bac0eb5f9c721c54
Contract transaction send: TransactionHash: 0x7747500b881c8da44efbc3b5d1c2c762f1cd52d2dd74050edbfed10e51a29d8a waiting to be mined...
...
Contract mined! Address: 0x0bb1d7a6b31f7a7e23e6d902bac0eb5f9c721c54
[object Object]
И вот мы добавляем в контракт 2 пользователей:
> salaryInfo.addUser(123, "User 123", "123 drive way, the uncentralised kingdom", 100, {from:web3.eth.accounts[0], data: salaryInfoCompiled.SalaryInfo.code, gas: 500000});
"0x7c22797d6b7717beb398a65159b1009fba3bbc9e4917ee1584bed60ea74eac11"
> salaryInfo.addUser(234, "User 234", "234 drive way, the uncentralised kingdom", 200, {from:web3.eth.accounts[0], data: salaryInfoCompiled.SalaryInfo.code, gas: 500000});
"0xed197c9a6fbc70c19cc95bcdc6943e38736c080052e9e1a4f7562216d6de4c78"
Получим количество пользователей:
> var numberOfUsers = salaryInfo.getUsersCount();
undefined
> numberOfUsers
2
Получим информацию для первого пользователя:
> salaryInfo.getUser(0)
[123, "User 123", "123 drive way, the uncentralised kingdom", 100]
И второй пользователь:
> var user2 = salaryInfo.getUser(1);
undefined
> user2
[234, "User 234", "234 drive way, the uncentralised kingdom", 200]
Начиная с Solidity 0.8.0 вы можете напрямую возвращать структуру. Вот простой пример договора:
pragma solidity ^0.8.0;
contract Example {
struct Store {
string id;
uint time;
}
mapping (address => Store) public purchases;
function set(string memory _id, uint _time) public returns(bool) {
purchases[msg.sender].id = _id;
purchases[msg.sender].time = _time;
return true;
}
function get() public view returns(Store memory) {
return purchases[msg.sender];
}
}
Если вы должны использовать любую версию Solidity <0.8.0, вам нужно добавить это, чтобы приведенный выше код работал:
pragma experimental ABIEncoderV2;
Вот пример из моей работы:
function getChannel(bytes32 channelId) returns(
address addr0,
address addr1,
uint8 phase,
uint challengePeriod,
uint closingBlock,
bytes state,
uint sequenceNumber,
bytes evidence0,
bytes evidence1
) {
addr0 = channels[channelId].addr0;
addr1 = channels[channelId].addr1;
phase = channels[channelId].phase;
challengePeriod = channels[channelId].challengePeriod;
closingBlock = channels[channelId].closingBlock;
state = channels[channelId].state;
sequenceNumber = channels[channelId].sequenceNumber;
evidence0 = channels[channelId].evidence0;
evidence1 = channels[channelId].evidence1;
}
Это возвращает
[
'0xe7d3b0123a4f0294e06d212876ade6277b47f473',
'0x3e4280efa3dd3014ca26022ac7dfe8e6c3070c67',
{ [String: '0'] s: 1, e: 0, c: [ 0 ] },
{ [String: '1'] s: 1, e: 0, c: [ 1 ] },
{ [String: '0'] s: 1, e: 0, c: [ 0 ] },
'0x2222',
{ [String: '1'] s: 1, e: 0, c: [ 1 ] },
'0x',
'0x'
]
Не самый читаемый, но это жизнь!
Вы можете вернуть структуру только из функции для внутренних вызовов в контракте.
Одним из возможных подходов было бы вернуть содержимое структуры в виде массива.
Используя pragma experimental ABIEncoderV2
вы можете вернуть структуру и прочитать ее через web3js.
Вот простой пример договора:
pragma solidity ^0.5.12;
pragma experimental ABIEncoderV2;
contract Example {
struct Store {
string id;
uint time;
}
mapping (address => Store) public purchases;
function set(string memory _id, uint _time) public returns(bool) {
purchases[msg.sender].id = _id;
purchases[msg.sender].time = _time;
return true;
}
function get() public view returns(Store memory) {
return purchases[msg.sender];
}
}
Код JavaScript для чтения структуры:
Example.methods.get().call({from: userAddress})
.then(function(result){
console.log(result[0]);
console.log(result[1]);
});
Амер Амин
ародригесдонайр
Прашант Прабхакар Сингх