Sé que puedo devolver matrices de bytes dinámicas en Solidity, como en el siguiente código:
function createMemoryArray(uint size) returns (bytes) {
// Dynamic memory arrays are created using `new`:
uint[2][] memory arrayOfPairs = new uint[2][](size);
// Create a dynamic byte array:
bytes memory b = new bytes(200);
for (uint i = 0; i < b.length; i++)
b[i] = byte(i);
return b;
}
Pero, ¿hay alguna forma de devolver algo como una matriz dinámica de cadenas? Siento que esto es solo un detalle de implementación en Solidity, pero sería genial si simplemente serializara todo bien para mí.
Todavía no, ya que esto requiere dos niveles de matrices dinámicas (la cadena es una matriz dinámica en sí misma). Doc
Sin embargo, puede devolver una matriz de Bytes32 (tamaño fijo de 32 bytes), por lo que puede intentar hacer algo como esto (puede copiar y pegar en Remix para probarlo)
pragma solidity ^0.4.11;
contract ArrayOfBytes32 {
address creator;
bytes32[10] bytesArray; // size must be fixed
function ArrayRR()
{
creator = msg.sender;
uint8 x = 0;
while(x < bytesArray.length)
{
bytesArray[x] = "myString";
x++;
}
}
function getArray() constant returns (bytes32[10])
{
return bytesArray;
}
function getValue(uint8 x) constant returns (bytes32)
{
return bytesArray[x];
}
}
Tenga en cuenta que tendrá que usar web3.toAcsii()
doc para convertir el resultado si usa web3 para interactuar con su contrato
Es un problema antiguo... Pero, para los recién llegados y para completar, no hay problemas en Solidity para devolver matrices dinámicas de pares o matrices dinámicas de cadenas, si se usa el compilador moderno (probado con 0.5.6
) y pragma ABI experimental :
pragma experimental ABIEncoderV2;
...
function createMemoryArray(uint size) public pure returns (uint[2][] memory) {
uint[2][] memory b = new uint[2][](size);
for (uint i=0; i < b.length; i++) {
b[i][0] = i;
b[i][1] = i * 2;
}
return b;
}
function createStringArray(uint size) public pure returns (string[] memory) {
string[] memory b = new string[](size);
for (uint i=0; i < b.length; i++) {
b[i] = "test";
}
return b;
}
Devolver matrices dinámicas de estructura en una función.
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
contract Money {
struct People{
uint id;
string name;
uint amount;
}
mapping (uint => People) public peoples;
event votedEvent(uint indexed _candidateId);
uint public candidateConut;
constructor() public {
candidateConut = 0;
addCandidate("Holder 1");
addCandidate("Holder 2");
}
function addCandidate(string memory _name) public {
peoples[candidateConut] = People(candidateConut,_name,0);
candidateConut++;
}
//return Single structure
function get(uint _candidateId) public view returns(People memory) {
return peoples[_candidateId];
}
//return Array of structure Value
function getPeople() public view returns (uint[] memory, string[] memory,uint[] memory){
uint[] memory id = new uint[](candidateConut);
string[] memory name = new string[](candidateConut);
uint[] memory amount = new uint[](candidateConut);
for (uint i = 0; i < candidateConut; i++) {
People storage people = peoples[i];
id[i] = people.id;
name[i] = people.name;
amount[i] = people.amount;
}
return (id, name,amount);
}
//return Array of structure
function getPeoples() public view returns (People[] memory){
People[] memory id = new People[](candidateConut);
for (uint i = 0; i < candidateConut; i++) {
People storage people = peoples[i];
id[i] = people;
}
return id;
}
}
¿Es posible devolver una matriz dinámica de cadenas ( string[] ) desde una función de Solidity?
Sí, puede serializarlo en bytes y deserializarlo nuevamente en string[].
En tu contrato inteligente:
function toBytes(string[] strArray)
private
pure
returns(bytes serialized) {
uint startindex = 0;
uint endindex = strArray.length - 1;
require(endindex >= startindex);
if (endindex > (strArray.length - 1)) {
endindex = strArray.length - 1;
}
//64 byte is needed for safe storage of a single string.
//((endindex - startindex) + 1) is the number of strings we want to pull out.
uint offset = 64 * ((endindex - startindex) + 1);
bytes memory buffer = new bytes(offset);
string memory out1 = new string(32);
for (uint i = startindex; i <= endindex; i++) {
out1 = strArray[i];
stringToBytes(offset, bytes(out1), buffer);
offset -= sizeOfString(out1);
}
return (buffer);
}
function stringToBytes(uint _offst, bytes memory _input, bytes memory _output)
private
pure {
uint256 stack_size = _input.length / 32;
if (_input.length % 32 > 0) stack_size++;
assembly {
stack_size: = add(stack_size, 1) //adding because of 32 first bytes memory as the length
for {
let index: = 0
}
lt(index, stack_size) {
index: = add(index, 1)
} {
mstore(add(_output, _offst), mload(add(_input, mul(index, 32))))
_offst: = sub(_offst, 32)
}
}
}
function sizeOfString(string memory _in)
private
pure
returns(uint _size) {
_size = bytes(_in).length / 32;
if (bytes(_in).length % 32 != 0)
_size++;
_size++; // first 32 bytes is reserved for the size of the string
_size *= 32;
}
}
Luego, para deserializarlo de nuevo a string[] (usando js), use la siguiente función:
function hexBytesToStr(hex) {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
let v = parseInt(hex.substr(i, 2), 16);
if (v) str += String.fromCharCode(v);
}
let params = [];
let res = "";
for (let i = 0; i <= str.length; i++) {
if (str.charCodeAt(i) > 31) {
res = res + str[i];
}
else {
params.push(res);
res = "";
}
}
params.pop();
return params;
}
usuario9402
Roberto Zaremba
bytes32[]
)?Roberto Zaremba
bytes32[]
). Lo que no puede es devolver un objeto que combina dos niveles de matrices dinámicas.Andrei
Oliver Rydzi
Zeeshan Ahmad Khalil
0x00000000.... ,0x0000000....., ....
en solidez. Además, en la versión más nueva, tenemos que agregar unamemory
palabra clave en el tipo de devolución, lo que me está creando el problema, creo.