Ungültiger JSON-RPC-Antwortfehler für sendTransaction auf Infura + Ropsten-Knoten + Truffle-Konsole

Aufrufe funktionieren, aber Transaktionen werfen den Fehler -

Fehler: Ungültige JSON-RPC-Antwort: ""

Ich verwende web3 v0.19.0 & Truffle v3.4.9. Bereitstellung eines Vertrags mit Truffle,
truffle migrate --network ropsten
der erfolgreich API und Vertragsadresse bereitstellt.

Mein Web3-Anbieter und mein Ropsten-Netzwerk (Infura-Knoten) sind in truffle.js über dem Projekt „react-auth-box “ definiert .

Ich öffne truffle console --network ropstenund definiere web3 -

var Web3 = require('web3')
let web3 = new Web3()
web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/my_access_token_here')) 

Es gibt kein Standardkonto
web3.eth.defaultAccount(gibt null zurück)
web3.eth.accounts(gibt [] zurück)

Standardkonto festlegen,
web3.eth.defaultAccount = '0xpersonalaccount'

Vertragsinstanz definieren,
let contract = web3.eth.contract(abi).at(address)

Bis jetzt alles gut und Anrufe funktionieren -
contract.checkIdExists.call(1, {'from': account, 'to': address})
(gibt '0x0000000000' zurück)

contract.fetchDataById.call(1, {'from': account, 'to': address})
(Gibt '0x' zurück)

1. Transaktionen schlagen fehl -
contract.addRecord.sendTransaction(1, 'fjdnjsnkjnsd', '03:00:21 12-12-12', 'true', '', {'from': account, 'to': address})

Fehler: Ungültige JSON-RPC-Antwort: „“ bei Object.InvalidResponse (/var/www/html/react-auth-box/node_modules/web3/lib/web3/errors.js:38:16) bei HttpProvider.send (/var /www/html/react-auth-box/node_modules/web3/lib/web3/httpprovider.js:91:22) unter RequestManager.send (/var/www/html/react-auth-box/node_modules/web3/lib /web3/requestmanager.js:58:32) bei Eth.send [als sendTransaction] (/var/www/html/react-auth-box/node_modules/web3/lib/web3/method.js:145:58) bei SolidityFunction.sendTransaction (/var/www/html/react-auth-box/node_modules/web3/lib/web3/function.js:167:26) bei evalmachine.:1:20 bei ContextifyScript.Script.runInContext (vm.js :53:29) bei Object.runInContext (vm.js:108:6) bei TruffleInterpreter.interpret (/home/shivam/.npm-global/lib/node_modules/truffle/build/cli.bundled.js:213786:17). ) bei gebunden (domain.js:301:14)

2. Lässt mich denken, dass ich wahrscheinlich zuerst das Konto entsperren muss (oder?)
web3.personal.unlockAccount(account, password)

Fehler: Ungültige JSON-RPC-Antwort: „“ bei Object.InvalidResponse (/var/www/html/react-auth-box/node_modules/web3/lib/web3/errors.js:38:16) bei HttpProvider.send (/var /www/html/react-auth-box/node_modules/web3/lib/web3/httpprovider.js:91:22) unter RequestManager.send (/var/www/html/react-auth-box/node_modules/web3/lib /web3/requestmanager.js:58:32) bei Personal.send [als unlockAccount] (/var/www/html/react-auth-box/node_modules/web3/lib/web3/method.js:145:58) bei evalmachine.:1:15 bei ContextifyScript.Script.runInContext (vm.js:53:29) bei Object.runInContext (vm.js:108:6) bei TruffleInterpreter.interpret (/home/shivam/.npm-global/lib /node_modules/truffle/build/cli.bundled.js:213786:17) bei gebunden (domain.js:301:14) bei REPLServer.runBound [als eval] (domain.js:314:12)

Läuft mittlerweile ziemlich ahnungslos. Jede Unterstützung wird geschätzt. Vielen Dank!

Infura unterstützt sendTransaction nicht, Sie müssen die Schlüssel auf Ihrer Seite verwalten und signierte Transaktionen mit sendRawTransaction senden. Um eine Transaktion zu signieren, können Sie ethereumjs-tx github.com/ethereumjs/ethereumjs-tx verwenden
Danke Ismael, das hat geholfen! Ich gehe davon aus, dass der Infura-Knoten nicht über das defaultAccount (oder so etwas) verfügt - ein wenig verwirrt über die genaue Begründung.
@ShivamD Ich glaube, der Grund dafür ist, dass Infura Ihre privaten Schlüssel nicht hält. Dies bedeutet, dass sie keine Transaktion in Ihrem Namen unterzeichnen können. Weitere Informationen finden Sie in diesem Beitrag: ethereum.stackexchange.com/questions/6905/…

Antworten (3)

Lassen Sie mich die vollständige Antwort hier posten (Dank an @Ismael).

Relevante Pakete -
web3@0.18.2
ethereumjs-tx@1.3.3 crypto
-js

const Web3 = require('web3')  
let web3 = new Web3()  
web3.providers.HttpProvider('https://ropsten.infura.io/my_access_token_here'))  
let contract = web3.eth.contract(abi).at(address)  
var coder = require('web3/lib/solidity/coder')  
var CryptoJS = require('crypto-js')  
var privateKey = new Buffer(myPrivateKey, 'hex')  

var functionName = 'addRecord'  
var types = ['uint','bytes32','bytes20','bytes5','bytes']  
var args = [1, 'fjdnjsnkjnsd', '03:00:21 12-12-12', 'true', '']  
var fullName = functionName + '(' + types.join() + ')'  
var signature = CryptoJS.SHA3(fullName,{outputLength:256}).toString(CryptoJS.enc.Hex).slice(0, 8)  
var dataHex = signature + coder.encodeParams(types, args)  
var data = '0x'+dataHex  

var nonce = web3.toHex(web3.eth.getTransactionCount(account))  
var gasPrice = web3.toHex(web3.eth.gasPrice)  
var gasLimitHex = web3.toHex(300000) (user defined)  
var rawTx = { 'nonce': nonce, 'gasPrice': gasPrice, 'gasLimit': gasLimitHex, 'from': account, 'to': address, 'data': data}  
var tx = new Tx(rawTx)  
tx.sign(privateKey)  
var serializedTx = '0x'+tx.serialize().toString('hex')  
web3.eth.sendRawTransaction(serializedTx, function(err, txHash){ console.log(err, txHash) })   

(Gibt '0xf802614fd6a53cb372752634630265063d0b48fec12ea8f5ed363de1d4bd372d' zurück)

web3.eth.getTransaction('0xf802614fd6a53cb372752634630265063d0b48fec12ea8f5ed363de1d4bd372d', console.log)

(Druckt Transaktionsdaten)
(Siehe hier )

wo wird myPrivateKeynormalerweise auf Ubuntu gespeichert, wenn es mit Geth erstellt wird

Größer als web1.0 ändern.

var myPrivateKey = "xxxxxx";
var privateKey = new Buffer(myPrivateKey, 'hex')

var functionName = 'add token';
var types = ['uint', 'bytes32', 'string', 'bool', 'bytes'];
var args = [123, '0xdf3234', '03:00:21 12-12-12', true, '0xdf3234'];
var fullName = functionName + '(' + types.join() + ')';
var signature = CryptoJS.SHA3(fullName, { outputLength: 256 }).toString(CryptoJS.enc.Hex).slice(0, 8)
var dataHex = signature + Web3.eth.abi.encodeParameters(types, args)
var data = '0x' + dataHex;
// console.log(99, dataHex)

var rawTx = {
    nonce: Web3.utils.toHex(await Web3.eth.getTransactionCount(cfg.addr.accountA).then(data => data)),
    gasPrice: Web3.utils.toHex(await Web3.eth.getGasPrice().then(data => data)),
    gasLimit: Web3.utils.toHex(300000), // Web3.toHex(300000)
    // from: '',
    to: cfg.addr.accountB,
    value: Web3.utils.toHex(10 ** 16),
    data
}

var tx = new Tx(rawTx)
tx.sign(privateKey)
var serializedTx = '0x' + tx.serialize().toString('hex')

const res = await Web3.eth.sendSignedTransaction(serializedTx)
    .on('transactionHash', function (hash) {
        console.log(100, hash)
    })
    .on('receipt', function (receipt) {
        console.log(101, receipt)
        return receipt;
    })
    .on('confirmation', function (confirmationNumber, receipt) {
        // console.log(102, confirmationNumber, receipt)
    })
    .on('error', (e) => {
        console.log(103, e)
    })

Bearbeiten: Ja, wenn eine Transaktion an den Infura-Knoten gesendet wird, muss sie vorher erstellt und signiert werden, da sie nur die eth_sendRawTransactionJSON-RPC-Methode unterstützt.

Es ist nicht mehr erforderlich, die ethereumjs-tx-Bibliothek zu verwenden, um Transaktionen durchzuführen, Sie können dies nur mit Core web3.js 1.0 tun, Sie brauchen nichts anderes,

Automatisches Signieren von Transaktionen nur mit web3.js 1.0 unter Verwendung web3.eth.sendTransaction()des bereitgestellten privaten Schlüssels des sendenden Kontos:

Wenn Sie web3.eth.defaultAccount angeben, fügen Sie seinen privaten Schlüssel in web3.eth.accounts.wallet hinzu (auch als Schlüsselspeicher bezeichnet).

...   
web3.eth.wallet.add('The private key of the sending account')
...

Andernfalls hat die web3.js-API keine Möglichkeit, eine Transaktion zu signieren, da sie nicht weiß, wo sich der private Schlüssel von defautlAccount befindet, und dies tun wird:

"Error: Returned error: The method eth_sendTransaction does not exist/is not available"

Hinweis: Sie müssen auch die Sicherheitsimplikationen berücksichtigen, wenn der private Schlüssel des Benutzers in seinem lokalen Browserspeicher gespeichert wird.

Wenn Sie also beispielsweise einen lokalen TestRPC mit gesperrten Konten verwenden würden, könnten Sie, um dasselbe zu tun, die unlockAccountFunktion auf dem Konto verwenden, das Sie zum Signieren verwenden möchten, und dann eine Transaktion signieren, jedoch in der oben erläuterten Variante ( eine „Wallet“ hinzufügen), alles, was Sie tun müssen, ist

...
web3.eth.defaultAccount = '0xpersonalaccount'
web3.eth.wallet.add('The private key of your personal account')
...

und jetzt können Sie es auch verwenden web3.eth.sendTransaction(), ohne eine from:Eigenschaft anzugeben und sie anschließend zu signieren, da web3.js sie lokal mit dem privaten Schlüssel dieses Standardkontos signiert und die Transaktion web3.eth.sendSignedTransaction()automatisch per sendet.

Dies funktioniert nicht, wenn eine Vertragsmethode über sendoder aufgerufen wirdcall
Ich kann den Kommentar von @PaulBerg genehmigen. Ich verwende methods.myMethod.send(siehe web3js.readthedocs.io/en/1.0/… ) und es schlägt fehl"Error: Returned error: The method eth_sendTransaction does not exist/is not available"
@Ronin, @Paul, Sie können nicht verwenden contract.methods.myMethod.send(), Sie müssen die Transaktion verwenden web3.eth.sendTransaction()oder web3.eth.sendSignedTransaction()erstellen und signieren, bevor Sie sie senden, wie ich in meiner ursprünglichen Antwort beschrieben habe. Um das zu verwenden eth_call, müssen Sie nichts in Bezug auf die Kontoverwaltung tun, außer den Absender anzugeben, da es nur zum Aufrufen von Nur-Lese-Funktionen (Ansicht) verwendet wird und den Status in der Blockchain nicht ändert (im Grunde keine Transaktion).