Las llamadas funcionan pero las transacciones arrojan el error :
Error: respuesta JSON RPC no válida: ""
Estoy usando web3 v0.19.0 y Truffle v3.4.9. Desplegando el contrato usando truffle,
truffle migrate --network ropsten
que proporciona con éxito la API y la dirección del contrato.
Mi proveedor web3 y la red ropsten (nodo infura) están definidos en truffle.js además del proyecto react-auth-box .
Abro truffle console --network ropsten
y defino web3 -
var Web3 = require('web3')
let web3 = new Web3()
web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/my_access_token_here'))
No hay una cuenta predeterminada
web3.eth.defaultAccount
(devuelve nulo)
web3.eth.accounts
(devuelve [])
Establecer cuenta predeterminada,
web3.eth.defaultAccount = '0xpersonalaccount'
Definir instancia de contrato,
let contract = web3.eth.contract(abi).at(address)
Todo bien hasta ahora y las llamadas funcionan -
contract.checkIdExists.call(1, {'from': account, 'to': address})
(Devuelve '0x0000000000')
contract.fetchDataById.call(1, {'from': account, 'to': address})
(Devuelve '0x')
1. Las transacciones fallan -
contract.addRecord.sendTransaction(1, 'fjdnjsnkjnsd', '03:00:21 12-12-12', 'true', '', {'from': account, 'to': address})
Error: respuesta JSON RPC no válida: "" en Object.InvalidResponse (/var/www/html/react-auth-box/node_modules/web3/lib/web3/errors.js:38:16) en HttpProvider.send (/var /www/html/react-auth-box/node_modules/web3/lib/web3/httpprovider.js:91:22) en RequestManager.send (/var/www/html/react-auth-box/node_modules/web3/lib /web3/requestmanager.js:58:32) en Eth.send [como sendTransaction] (/var/www/html/react-auth-box/node_modules/web3/lib/web3/method.js:145:58) en SolidityFunction.sendTransaction (/var/www/html/react-auth-box/node_modules/web3/lib/web3/function.js:167:26) en evalmachine.:1:20 en ContextifyScript.Script.runInContext (vm.js :53:29) en Object.runInContext (vm.js:108:6) en TruffleInterpreter.interpret (/home/shivam/.npm-global/lib/node_modules/truffle/build/cli.bundled.js:213786:17 ) en el límite (dominio.js:301:14)
2. Me hace pensar que probablemente deba desbloquear la cuenta primero (¿o sí?)
web3.personal.unlockAccount(account, password)
Error: respuesta JSON RPC no válida: "" en Object.InvalidResponse (/var/www/html/react-auth-box/node_modules/web3/lib/web3/errors.js:38:16) en HttpProvider.send (/var /www/html/react-auth-box/node_modules/web3/lib/web3/httpprovider.js:91:22) en RequestManager.send (/var/www/html/react-auth-box/node_modules/web3/lib /web3/requestmanager.js:58:32) en Personal.send [como unlockAccount] (/var/www/html/react-auth-box/node_modules/web3/lib/web3/method.js:145:58) en evalmachine.:1:15 en ContextifyScript.Script.runInContext (vm.js:53:29) en Object.runInContext (vm.js:108:6) en TruffleInterpreter.interpret (/home/shivam/.npm-global/lib /node_modules/truffle/build/cli.bundled.js:213786:17) en el límite (dominio.js:301:14) en REPLServer.runBound [como evaluación] (dominio.js:314:12)
Corriendo bastante despistado por ahora. Cualquier apoyo será apreciado. ¡Gracias!
Permítanme publicar la respuesta completa aquí (Créditos a @Ismael).
Paquetes relevantes:
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) })
(Devuelve '0xf802614fd6a53cb372752634630265063d0b48fec12ea8f5ed363de1d4bd372d')
web3.eth.getTransaction('0xf802614fd6a53cb372752634630265063d0b48fec12ea8f5ed363de1d4bd372d', console.log)
(Imprime los datos de la transacción)
(Consulte aquí )
myPrivateKey
normalmente se almacena en ubuntu cuando se hace con gethMayor que el cambio web1.0.
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)
})
Editar: Sí, al enviar una transacción al nodo Infura, debe crearse y firmarse de antemano, ya que solo admite el eth_sendRawTransaction
método JSON RPC.
Ya no es necesario usar la biblioteca ethereumjs-tx para realizar transacciones, puede hacerlo solo con core web3.js 1.0, no necesita más,
Firmar transacciones automáticamente usando solo web3.js 1.0, usando web3.eth.sendTransaction()
la clave privada proporcionada de la cuenta de envío:
Cuando especifique web3.eth.defaultAccount, agregue su clave privada en web3.eth.accounts.wallet (también conocido como almacén de claves).
...
web3.eth.wallet.add('The private key of the sending account')
...
De lo contrario, la API de web3.js no tiene forma de firmar una transacción porque no sabe dónde está la clave privada defautlAccount y lo hará:
"Error: Returned error: The method eth_sendTransaction does not exist/is not available"
Nota: también debe considerar las implicaciones de seguridad de almacenar la clave privada del usuario en el almacenamiento de su navegador local.
Entonces, por ejemplo, si usara un TestRPC local con cuentas bloqueadas, para hacer lo mismo, podría usar unlockAccount
la función en la cuenta que desea usar para firmar y luego firmar una transacción, pero en la variante explicada anteriormente ( agregando una 'billetera') todo lo que necesita hacer es
...
web3.eth.defaultAccount = '0xpersonalaccount'
web3.eth.wallet.add('The private key of your personal account')
...
y ahora puede usarlo web3.eth.sendTransaction()
incluso sin especificar una from:
propiedad y firmarla después, ya que web3.js lo firmará localmente usando la clave privada de esa cuenta predeterminada y enviará la transacción web3.eth.sendSignedTransaction()
automáticamente.
send
de ocall
methods.myMethod.send
(ver web3js.readthedocs.io/en/1.0/… ) y falla con"Error: Returned error: The method eth_sendTransaction does not exist/is not available"
contract.methods.myMethod.send()
, tendrá que usar web3.eth.sendTransaction()
o web3.eth.sendSignedTransaction()
para crear y firmar la transacción antes de enviarla, como describí en mi respuesta original. Para usar el eth_call
no necesita hacer nada relacionado con la administración de la cuenta, excepto especificar el remitente, ya que se usa solo para llamar a funciones de solo lectura (ver) y no modifica el estado en la cadena de bloques (básicamente no es una transacción).
ismael
Shivam D.
hhppj