Estoy almacenando datos en mi contrato usando un mapeo de estructuras.
Por ejemplo, supongamos que estoy almacenando información del empleado (nombre/dirección/salario), mapeada por su ID de empleado.
A través de un front-end web, me gustaría poder especificar una identificación de empleado y llamar a una función en mi contrato (usando Web3.JS) que devuelve la información del empleado.
¿Cómo puedo acceder a los datos si se devuelve una estructura? ¿Es eso posible?
Devuelve los campos de la estructura como variables de retorno separadas.
Editar: a partir de 2021, es posible devolver la estructura directamente. Ver esta respuesta .
Estoy ejecutando este código en mi cadena de bloques de desarrollo local usando el siguiente comando:
geth --datadir ~/devdata --dev --nodiscover \
--mine --minerthreads 1 --port 30301 \
--maxpeers 0 --verbosity 3 --rpc console
Su interfaz web debería poder enviar transacciones para insertar a los usuarios y llamar a las funciones para obtener la cantidad de usuarios y la información del usuario.
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);
}
}
Uso el stripCrLf
método (de How to load Solidity source file into geth ) para transformar la fuente formateada en una sola línea que se puede insertar dentro de la geth
consola. Alternativamente, busque una página web que elimine los saltos de línea de su código. Luego asigne su código a una variable de 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); }}'
El compilar el código:
> var salaryInfoCompiled = web3.eth.compile.solidity(salaryInfoSource);
Cargue el código en la cadena de bloques:
> 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);
}
}
}
)
Espere el siguiente mensaje para indicar que el contrato ha sido minado:
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]
Y aquí estamos agregando 2 usuarios al contrato:
> 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"
Vamos a obtener el número de usuarios:
> var numberOfUsers = salaryInfo.getUsersCount();
undefined
> numberOfUsers
2
Vamos a obtener la información para el primer usuario:
> salaryInfo.getUser(0)
[123, "User 123", "123 drive way, the uncentralised kingdom", 100]
Y el segundo usuario:
> var user2 = salaryInfo.getUser(1);
undefined
> user2
[234, "User 234", "234 drive way, the uncentralised kingdom", 200]
A partir de solidity 0.8.0, puede devolver una estructura directamente. Aquí hay un contrato de ejemplo simple:
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];
}
}
Si debe usar cualquier versión de solidez <0.8.0, debe agregar esto para que funcione el código anterior:
pragma experimental ABIEncoderV2;
Aquí hay un ejemplo de mi trabajo:
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;
}
esto vuelve
[
'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'
]
No es el más legible, ¡pero así es la vida!
Solo puede devolver una estructura de una función para llamadas internas en un contrato.
Un enfoque posible sería devolver el contenido de la estructura en una matriz.
Usando pragma experimental ABIEncoderV2
puede devolver una estructura y leerla a través de web3js.
Aquí hay un contrato de ejemplo simple:
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];
}
}
Código JavaScript para leer la estructura:
Example.methods.get().call({from: userAddress})
.then(function(result){
console.log(result[0]);
console.log(result[1]);
});
Amer Amén
arodriguezdonaire
Prashant Prabhakar Singh