Llamar a una matriz pública de estructuras usando web3

Buenos días.

Tengo una serie de estructuras como:

User[] public users;


struct User{
    uint idNum;
    string name;
    address userAddress;
}

Y estoy tratando de obtener la matriz de usuarios con web3.js usando:

contract = web3.eth.contract([ABI]).at("0x0..");
var users = contract.users();

Hasta ahora todo funciona bien, pero cuando trato de obtener el tamaño de la matriz, siempre obtengo 3; supongo que solo cuenta cuántos campos tiene cada usuario, pero lo que quiero es contar cuántos usuarios hay.

Entiendo que la variable "usuarios" (en JS) es una función y no una matriz per se, pero no puedo encontrar ninguna forma de interactuar directamente con la matriz.

Prueba var users = contract.users.lengthen tu .jsarchivo,
El resultado es 3 (aunque la matriz tiene 7 usuarios). Puedo obtener la información de cualquier usuario específico escribiendo su número manualmente contract.users(4) -> {idNum:4, name: "number 4", userAddress: "0x0.."}

Respuestas (2)

Prueba lo siguiente:

function getUsersCount() public constant returns(uint) {
    return users.length;
}

function getUser(uint index) public constant returns(uint, string, address) {
    return (users[index].idNum, users[index].name, users[index].userAddress);
}

Entonces debería poder usar las declaraciones:

> var numberOfUsers = contract.usersCount();
undefined
> numberOfUsers
5
> var user0 = contract.users(0)
[123, "User 123", "0xbeefee3ad17cd9aca6fd5343a53a513685c7e0ed"]
> var user1 = contract.getUser(1)
[234, "User 234", "0xbeefee3ad17cd9aca6fd5343a53a513685c7e0ed"]
> var lastUser = arrayStruct.users(numberOfUsers-1)
undefined
> lastUser
[567, "User 567", "0xbeefee3ad17cd9aca6fd5343a53a513685c7e0ed"]

Y respondiendo al comentario de Nikhil M, la siguiente declaración siempre devuelve 0 para mí. No sé si es una característica de diseño o un error.

> var users = contract.users.length
undefined
> users
0



Costo de gasolina

La llamada a contract.usersCount(), contract.users(x)y contract.getUser()no cambie los datos de la cadena de bloques y no cueste gasolina. de saludador ,

Ejecute el Greeter Para llamar a su bot, simplemente escriba el siguiente comando en su terminal:

greeter.greet();

Dado que esta llamada no cambia nada en la cadena de bloques, regresa instantáneamente y sin costo de gasolina. Deberías ver que te devuelve el saludo:

Este es el código de contrato que utilicé:

contract ArrayStruct {

    struct User {
        uint idNum;
        string name;
        address userAddress;
    }

    User[] public users;

    function addUser(uint _idNum, string _name, address _userAddress) public returns(uint) {
        users.length++;
        users[users.length-1].idNum = _idNum;
        users[users.length-1].name = _name;
        users[users.length-1].userAddress = _userAddress;
        return users.length;
    }

    function getUsersCount() public constant returns(uint) {
        return users.length;
    }

    function getUser(uint index) public constant returns(uint, string, address) {
        return (users[index].idNum, users[index].name, users[index].userAddress);
    }
}

Deberá pagar el gas por insertar el contrato en la cadena de bloques como se muestra en el gas: 1000000campo en la siguiente declaración:

var contract = arrayStructContract.new({
  from:web3.eth.accounts[0],
  data: arrayStructCompiled.ArrayStruct.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);
      }
    }
})

Y tendrá que pagar la gasolina cuando cambie los datos de la cadena de bloques, como se muestra gas: 500000en las siguientes declaraciones:

contract.addUser(123, "User 123", eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: arrayStructCompiled.ArrayStruct.code, 
  gas: 500000
});

contract.addUser(234, "User 234", eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: arrayStructCompiled.ArrayStruct.code, 
  gas: 500000
});
Este es un buen enfoque para el problema, pero esperaba obtener los datos usando solo JS para ahorrar algo de gasolina (users.length se actualizará de vez en cuando).
La llamada a contract.usersCount(), contract.users(x)y contract.getUser()no cambie los datos de la cadena de bloques y no cueste gasolina.
pero ¿no aumentará el costo de implementación? y ¿qué sucederá cuando se agregue/elimine un usuario?
He agregado los detalles sobre el costo de implementación a la respuesta en Gas Costo

Aquí está el código que uso... probablemente solo sea una solución, pero desde la consola de mi nodo uso:

var i = 4;
var j = 0;
while (i>3) {var x = contract.users.call(j);j++;var i = x.length} 
j-1

Entonces ese último j-1 debería imprimir la longitud de su lista