Aufrufen eines öffentlichen Arrays von Strukturen mit web3

Schönen Tag.

Ich habe eine Reihe von Strukturen wie:

User[] public users;


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

Und ich versuche, das Array von Benutzern mit web3.js zu erhalten, indem ich Folgendes verwende:

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

Bisher funktioniert alles gut, aber wenn ich versuche, die Größe des Arrays zu ermitteln, bekomme ich immer 3 - ich nehme an, es zählt nur, wie viele Felder jeder Benutzer hat, aber ich möchte zählen, wie viele Benutzer dort sind.

Ich verstehe, dass die Variable "users" (in JS) eine Funktion und kein Array an sich ist, aber ich kann einfach keine Möglichkeit finden, direkt mit dem Array zu interagieren.

Versuchen Sie var users = contract.users.lengthes in Ihrer .jsDatei,
Das Ergebnis ist 3 (obwohl das Array 7 Benutzer hat). Ich kann die Informationen zu einem bestimmten Benutzer abrufen, indem ich seine Nummer manuell eintippe. contract.users(4) -> {idNum:4, name: "number 4", userAddress: "0x0.."}

Antworten (2)

Versuche Folgendes:

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);
}

Sie sollten dann in der Lage sein, die Anweisungen zu verwenden:

> 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"]

Und als Antwort auf den Kommentar von Nikhil Mgibt die folgende Anweisung für mich immer 0 zurück. Ich weiß nicht, ob es ein Designfeature oder ein Bug ist.

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



Gaskosten

Der Aufruf an contract.usersCount(), ändert die Blockchain-Daten nicht contract.users(x)und contract.getUser()kostet kein Benzin. Von Greeter ,

Führen Sie den Greeter aus Um Ihren Bot anzurufen, geben Sie einfach den folgenden Befehl in Ihr Terminal ein:

greeter.greet();

Da dieser Aufruf nichts an der Blockchain ändert, kehrt er sofort und ohne Gaskosten zurück. Sie sollten sehen, dass es Ihren Gruß erwidert:

Dies ist der Vertragscode, den ich verwendet habe:

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);
    }
}

Sie müssen das Gas für das Einfügen des Vertrags in die Blockchain bezahlen, wie das gas: 1000000Feld in der folgenden Anweisung zeigt:

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);
      }
    }
})

Und Sie müssen das Gas bezahlen, wenn Sie die Blockchain-Daten ändern, wie gas: 500000in den folgenden Aussagen gezeigt wird:

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
});
Dies ist ein guter Ansatz für das Problem, aber ich wollte die Daten nur mit JS abrufen, um etwas Gas zu sparen (users.length wird von Zeit zu Zeit aktualisiert).
Der Aufruf an contract.usersCount(), ändert die Blockchain-Daten nicht contract.users(x)und contract.getUser()kostet kein Benzin.
aber erhöhen sich dadurch nicht die Bereitstellungskosten? und was passiert, wenn ein Benutzer hinzugefügt/entfernt wird?
Ich habe die Details zu den Bereitstellungskosten zur Antwort unter Gaskosten hinzugefügt

Hier ist der Code, den ich verwende ... wahrscheinlich nur eine Problemumgehung, aber von meiner Knotenkonsole aus verwende ich:

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

Dann sollte das letzte j-1 die Länge Ihrer Liste ausgeben