Wie erhalte ich Rückgabewerte, wenn eine Nichtansichtsfunktion aufgerufen wird?

Ich schreibe unten einen einfachen Vertrag, der alle Ergebnisse der Fragebögen für jede ID speichert.

contract answer{
  mapping(address => mapping(string => bool)) voters;

  struct qList {
    uint count; //The number of respondents
    mapping(address => mapping(uint => uint)) answer;
  }

  mapping(string => qList) questionnaires;

  function vote(string ID, uint qNum, uint ans) returns (bool) {
    if(voters[msg.sender][ID]) throw;
    voters[msg.sender][ID] = true;
    questionnaires[ID].count += 1;
    questionnaires[ID].answer[msg.sender][qNum] = ans;
    return true;
  }

  function getNumResult(string ID) constant returns (uint res) {
    return questionnaires[ID].count;
  }
}

Die Funktion votekann erfolgreich aufgerufen und abgebaut werden, aber ich kann den Rückgabewert von nicht erhalten vote.

Schätzen Sie es, wenn jemand die Ursache dafür und die Lösung empfehlen würde, um den Rückgabewert der Funktion mit Argumenten zu erhalten.

Antworten (3)

Zusammenfassung

Ihr Code wird wie erwartet ausgeführt, wenn ich ihn über die Konsole ausführe geth. Wenn es für Sie nicht funktioniert, versuchen Sie, das Gas zu erhöhen, das Sie mit Ihren Transaktionen senden.

Wie @Taylor Gerringin seiner Antwort angegeben, können Sie die Ergebnisse Ihrer Funktion möglicherweise nicht abrufen vote(), aber Ihr Code scheint in Ordnung zu sein.

Wenn Sie das Ergebnis Ihrer vote()Funktion wollen, die in Ihrem Beispiel eine Überprüfung ist, ob eine Person schon einmal abgestimmt hat, haben Sie diese Daten bereits in Ihren votersDaten.



Die Details

Ich habe Ihren Quellcode genommen und nur den Klassennamen von answerin geändert Answerund Ihren Kommentar von //in konvertiert /*...*/:

contract Answer {
  mapping(address => mapping(string => bool)) voters;

  struct qList {
    uint count; /* The number of respondents */
    mapping(address => mapping(uint => uint)) answer;
  }

  mapping(string => qList) questionnaires;

  function vote(string ID, uint qNum, uint ans) returns (bool) {
    if (voters[msg.sender][ID]) throw;
    voters[msg.sender][ID] = true;
    questionnaires[ID].count += 1;
    questionnaires[ID].answer[msg.sender][qNum] = ans;
    return true;
  }

  function getNumResult(string ID) constant returns (uint res) {
    return questionnaires[ID].count;
  }
}

Ich habe das CR-LF aus dem Code entfernt und die Leerzeichen reduziert und die folgende Anweisung in ausgeführt geth:

> var answerSource='contract Answer { mapping(address => mapping(string => bool)) voters; struct qList { uint count; /* The number of respondents */ mapping(address => mapping(uint => uint)) answer; } mapping(string => qList) questionnaires; function vote(string ID, uint qNum, uint ans) returns (bool) { if(voters[msg.sender][ID]) throw; voters[msg.sender][ID] = true; questionnaires[ID].count += 1; questionnaires[ID].answer[msg.sender][qNum] = ans; return true; } function getNumResult(string ID) constant returns (uint res) { return questionnaires[ID].count; }}'
undefined

Ich habe dann Ihren Code kompiliert und in meine Dev-Blockchain eingefügt:

> var answerCompiled = web3.eth.compile.solidity(answerSource);
undefined

> var answerContract = web3.eth.contract(answerCompiled.Answer.info.abiDefinition);
undefined 

> var answer = answerContract.new({
    from:web3.eth.accounts[0], 
    data: answerCompiled.Answer.code, gas: 2000000}, 
    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);
        }
    }
})

Contract transaction send: TransactionHash: 0x5b5eb3c6d2a4b43eff4444b71b762911ddc72e239d1d495b6bec7b2e6a738df0 waiting to be mined...

Ich wartete darauf, dass der Vertrag abgebaut wurde und bekam folgende Meldung:

Contract mined! Address: 0xe51ac93e4c28206f0f0296e5b6d66daf0a917bc3
[object Object]

Geprüft getNumResult():

> answer.getNumResult("idOne")
0

Abgestimmt:

> answer.vote("idOne", 1, 1, eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: answerCompiled.Answer.code,
  gas: 1000000
});
"0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699"

Wartete, bis die Transaktion abgebaut wurde, und überprüfte die Transaktion:

> eth.getTransaction("0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699")
{
  ...
  blockNumber: 6567,
  ...
}

Geprüft getNumResult():

> answer.getNumResult("idOne")
1

Eine weitere Stimme mit einer anderen ID gesendet:

> answer.vote("idTwo", 2, 1, eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: answerCompiled.Answer.code,
  gas: 1000000
});

Ergebnisse überprüft:

> answer.getNumResult("idTwo")
1

Eine weitere Stimme vom selben Konto mit derselben ID gesendet:

> answer.vote("idOne", 2, 1, eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: answerCompiled.Answer.code,
  gas: 1000000
});
"0xbbf9db6eb7c02571948002f56e3a7c56b6c7f55c2a4bbc70a244bb2afbf44e1f"

Und mir ist folgender Fehler aufgefallen:

PC 00000366: JUMP GAS: 976744 COST: 8 ERROR: invalid jump destination (PUSH1) 2

Der obige Fehler muss aus der Aussage in Ihrem Code generiert worden sein, throwwenn dieselbe ID von demselben Konto gewählt wird:

if (voters[msg.sender][ID]) throw;

Ich habe dann eine weitere Stimme von meinem zweiten Konto gesendet:

> answer.vote("idOne", 2, 1, eth.accounts[1], {
  from:web3.eth.accounts[1], 
  data: answerCompiled.Answer.code,
  gas: 1000000
});

Und die Ergebnisse wurden wie erwartet aktualisiert:

> answer.getNumResult("idOne")
2
Hat für mich funktioniert, aber ich musste requiremit der vom Operator negierten Bedingung !anstelle von verwenden throw.

Es ist derzeit nicht möglich, Werte von Funktionen zurückzugeben, die die Blockchain verändern. Um einen Rückgabewert zu erhalten, können Sie Funktionen als "pure" oder "view" markieren .

Für zustandsändernde Funktionen ist die einzige Möglichkeit, Informationen „zurückzugeben“, die Verwendung von Solidity-Ereignissen, die als LOG-Opcodes in der Ethereum Virtual Machine zusammenfließen.

Ich frage mich , warum ich von meiner nicht konstanten Funktion keinen Rückgabewert erhalten kann. Ich muss Ereignisse verwenden?
@Eamorr Aus rein technischer Sicht ist es nicht unmöglich, aber aktuelle Client-Implementierungen eignen sich nicht für eine solche Funktionalität
Macht es also Sinn, "returns (bool)" in die Funktion "vote()" zu schreiben?
@Aniket ja, es ist sinnvoll, wenn die Funktion von einer anderen Smart-Contract-Funktion aufgerufen wird
Wie bekommen wir, dass dies die akzeptierte Antwort ist? Das obige ist irreführend.

Mit nicht konstanter Funktion votekönnen Sie den Transaktions-Hash nur sofort zurückerhalten, da die Transaktion möglicherweise nie abgebaut wird. Oder es könnte mehrere Blöcke dauern, wie durch „Warten auf zu minende Transaktion ...“ angezeigt. Empfohlene Überprüfung: Was ist der Unterschied zwischen einer Transaktion und einem Anruf?

Veranstaltungen

Ereignisse werden benötigt, um den "Rückgabewert" von zu erhalten vote.

Beispiel zum Hinzufügen und Auslösen eines event:

contract answer{
  // ...
  event VoteEvent(string ID, bool returnValue);

  function vote(string ID, uint qNum, uint ans) returns (bool) {
    // ...
    VoteEvent(ID, true);
    return true;
  }
}

Siehe Vertragsereignisse für die verschiedenen Möglichkeiten, Ereignisdaten mit web3.js zu überwachen und abzurufen.

Macht es also Sinn, "returns (bool)" in die Funktion "vote()" zu schreiben?
@AK Wenn votevielleicht return false, zum Beispiel wenn Sie bereits abgestimmt haben, könnte der Rückgabewert hilfreich sein, damit andere Verträge Dinge wie tun können if (!someContract.vote("ak", 7, 2)) {...}. Rückgabewerte können von anderen Verträgen verwendet werden, aber web3.js kann nur Ereignisse verwenden. Wenn dies immer der Fall ist return true, kann der boolesche Wert wahrscheinlich entfernt und das Ereignis zu etwas wie vereinfacht werden UserVoted(string ID).
hab es komplett hinbekommen