Abrufen von Daten aus Smart Contracts mit sendTransaction

Nehmen wir einen sehr einfachen Smart Contract, der eine Funktion hat, bei der Sie eine Zahl senden und das Quadrat zurückgeben. Es hat eine andere Funktion, die eine feste Zeichenfolge zurückgibt.

contract MyContract {
  uint public version;
  address public previousPublishedVersion;

  function ping() returns (string param){
    param = "pong";
  }

  function squareNumber(uint num) returns (uint256 numSqr) {
    numSqr = (num * num);
  }
}

Nun zur Bereitstellung des Vertrags, den ich verwende

myContract.new({
  data: MyContract.compiled_code,
  gas: gasNeeded * ethConfig.gas_factor,
  from: ethConfig.primary_address
}, (err, myContract) => {
    if(!err) {
     if(!myContract.address) {
         console.log('contract trasnaction hash ' + myContract.transactionHash)
     } else {
        console.log('contract address ' + myContract.address)
        resolve({
         primary_address: ethConfig.primary_address,
         contract_address: myContract.address,
         gas_estimate: gasNeeded
        })
     }
  } else {
    reject(err)
  }
});

Dies löst zwei Rückrufe aus, einen mit dem Transaktions-Hash und einen mit der Adresse, sobald sie abgebaut wurde. Diese Methode ist jedoch nicht für sendTransaction. Ich habe gelesen, dass die Verwendung getTransactionReceiptoder Überprüfung von Blocknummern eine gute Möglichkeit ist, um zu überprüfen, ob die Transaktion abgebaut wurde oder nicht.

  myContract.ping.call(null, (err, data) => {
    if (err) {
      reject(err)
    } else {
      resolve({
        primary_address: ethConfig.primary_address,
        returnValue: data
      })
    }
  })

Aber zum Quadrieren der Zahl verwende ich

  myContract.squareNumber.estimateGas(10, (err, gasNeeded) => {
    if (err) reject(err)
    myContract.squareNumber.sendTransaction(
      10,
      {
        gas: gasNeeded * config.ethConfig.gas_factor,
        from: config.ethConfig.primary_address
      }, (err, data) => {
      if (err) reject(err)
      resolve({
        primary_address: config.ethConfig.primary_address,
        numSquare : data
      })
    })
  })

Nun, für eine callFunktion kann ich die Daten direkt abrufen, ohne dass Mining durchgeführt werden muss, aber die Dokumente sagen, dass der von sendTransaction() zurückgegebene Wert der Hash davon ist, und dann müssen wir verwenden getTransactionReceipt(), um tatsächlich zu bestätigen, wann der Block abgebaut wurde .

Meine Frage ist einfach, wie genau strukturiere ich meinen web3jsCode, um den zurückgegebenen Wert (10*10) von der solidity-Funktion zu erhalten squareNumber().

Ich habe alle oben gezeigten APIs in Versprechen verpackt, aber diesen Teil einfach übersprungen, da er lang ist und in keiner Weise mit web3js zusammenhängt.

Antworten (2)

Nach dem Hinzufügen eines Ereignisses wie SquareComputed(siehe So erhalten Sie Werte, die von nicht konstanten Transaktionsfunktionen zurückgegeben werden? ) und des Beispiels für web3.js- Vertragsereignisse

var event = myContractInstance.MyEvent({valueA: 23} [, additionalFilterObject])

// watch for changes
event.watch(function(error, result){
  if (!error)
    console.log(result);
});

dies würde zu Code führen wie:

var event = myContractInstance.SquareComputed({});

// watch for changes
event.watch(function(error, result){
  if (!error)
    resolve({
        primary_address: config.ethConfig.primary_address,
        numSquare : result  // need to access the properties of result to obtain the actual square 
    })
  event.stopWatching();
});

Machen Sie vorher das oben Gesagte myContractInstance.squareNumber.sendTransaction. Das resolve({numSquare:...})im Originalcode sollte watchwie oben in das Innere verschoben werden.

Andere web3.js-APIs wie z. B. web3.eth.filterkönnen ebenfalls verwendet werden (siehe Wie rufe ich die Voted-Ereignisse von The DAO ab ).

Diese Frage lautet: "Wie genau strukturiere ich meinen web3js-Code, um den zurückgegebenen Wert (10*10) von der Solidity-Funktion squareNumber() zu erhalten", ansonsten siehe Was ist der Unterschied zwischen einer Transaktion und einem Aufruf? .

Ich habe verstanden, was Sie geschrieben haben, und die Links, aber wenn ich mehrere Instanzen dieses Vertrags in der Blockchain erstellt habe, sagen wir, jede Person hat ihre eigene eindeutige Vertragsinstanz bereitgestellt, dann event.watchwird die Verwendung problematisch, da alle ausgelösten Ereignisprotokolle erfasst werden.
Wenn jeder Benutzer seinen eigenen Vertrag und seine eigene Benutzeroberfläche hat, könnte das obige funktionieren. Wenn jeder Benutzer mehrere Verträge hat, könnte vielleicht ein Array verwendet werden wie: event[i] = myContractInstance[i].SquareComputed({}). Eine andere Möglichkeit besteht darin, einen indizierten Parameter für das Ereignis wie userId zu haben und danach zu filtern wie event = myContractInstance.MyEvent({userId: 23}(Muss möglicherweise eine separate Frage stellen, wenn wir zu abstrakt werden und spezifisch sein müssen.)

Mit Web3.js v1.0.0 können Sie das Ereignis erhalten, das von Ihrer SquareComputed-Transaktion ausgelöst wird ( sendTransation()äquivalente Methode ist jetzt send()), siehe send() returnin der Dokumentation