Ethereum 将已签名的事务发送到Ropsten
使用web3js调用不需要签名的函数很容易(例如,不更新合同状态的函数)。然而,除了手动解锁我的MetaMask钱包和在环境中调用函数之外,还不清楚如何调用需要签名的函数 在第一次将我的dapp部署到Ropsten之后,我需要调用Ethereum 将已签名的事务发送到Ropsten,ethereum,web3js,Ethereum,Web3js,使用web3js调用不需要签名的函数很容易(例如,不更新合同状态的函数)。然而,除了手动解锁我的MetaMask钱包和在环境中调用函数之外,还不清楚如何调用需要签名的函数 在第一次将我的dapp部署到Ropsten之后,我需要调用createItem(字符串名称,uint价格)100次来填充items数组。因为我不想在混音中手动操作,所以我想写一个自动操作的脚本 除了web3js之外,我还需要ethereumjs-tx以编程方式签署事务,而无需使用MetaMask。我还需要有我的帐户和私钥。根据
createItem(字符串名称,uint价格)
100次来填充items
数组。因为我不想在混音中手动操作,所以我想写一个自动操作的脚本
除了web3js
之外,我还需要ethereumjs-tx
以编程方式签署事务,而无需使用MetaMask。我还需要有我的帐户
和私钥
。根据所有这些信息和官方web3js文档,我得出以下结论:
// Call an external function programatically
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io"))
const account = "ACCOUNT_ADDRESS"
const privateKey = new Buffer('PRIVATE_KEY', 'hex')
const contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS, {
from: account,
gas: 3000000,
})
const functionAbi = contract.methods.myFunctionName(myArgument).encodeABI()
let estimatedGas
contract.methods.myFunctionNAme(myArgument).estimateGas({
from: account,
}).then((gasAmount) => {
estimatedGas = gasAmount.toString(16)
})
const txParams = {
gasPrice: '0x' + estimatedGas,
to: CONTRACT_ADDRESS,
data: functionAbi,
from: account,
}
const tx = new Tx(txParams)
tx.sign(privateKey)
const serializedTx = tx.serialize()
web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).
on('receipt', console.log)
代码运行,但txParams
实际上缺少一个键:nonce
。运行此操作时,会出现以下错误:
Unhandled rejection Error: Returned error: nonce too low
以下是我的问题:
nonce
参数nonce
。因此,我添加了以下代码:
let nonce
web3.eth.getTransactionCount(account).then(_nonce => {
nonce = _nonce.toString(16)
})
const txParams = {
gasPrice: '0x' + gasPrice,
to: CONTRACT_ADDRESS,
data: functionAbi,
from: account,
nonce: '0x' + nonce,
}
但现在我不断遇到这个例外:
未处理的拒绝错误:返回错误:rlp:输入字符串太长
对于uint64,解码为
(types.Transaction)(types.txdata).AccountNonce
Google搜索没有任何帮助,只是让我找到了这个包含异常处理程序的文件()。有人知道如何解决这个问题吗?通常看起来是正确的。我唯一想问的问题是,您打算如何加载私钥?您需要提示输入私钥,或者导入/读取密钥库并提示输入密码。您可以使用来实现这一点(参见示例代码部分)
nonce
只是用于为帐户订购交易的递增数字。要获得正确的值,只需使用web3.eth.getTransactionCount(account)
编辑-使用带有锁定帐户的Ganache运行示例(--secure
选项):
SimpleContract.sol
pragma solidity ^0.4.19;
contract SimpleContract {
uint public val = 4;
function increment(uint amt) public {
val += amt;
}
function get() public constant returns (uint) {
return val;
}
}
test.js
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const provider = new Web3.providers.HttpProvider("http://localhost:8545");
const web3 = new Web3(provider);
const account = '0x9a6d82ef3912d5ab60473124bccd2f2a640769d7'; // Ganache
const privateKey = Buffer.from('70f1384b24df3d2cdaca7974552ec28f055812ca5e4da7a0ccd0ac0f8a4a9b00', 'hex');
const contractAddress = '0x6dd7c1c13df7594c27e0d191fd8cc21efbfc98b4'; // Deployed manually
const abi = [{"constant":true,"inputs":[],"name":"val","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amt","type":"uint256"}],"name":"increment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}];
const contract = new web3.eth.Contract(abi, contractAddress, {
from: account,
gasLimit: 3000000,
});
const contractFunction = contract.methods.increment(3);
const functionAbi = contractFunction.encodeABI();
let estimatedGas;
let nonce;
console.log("Getting gas estimate");
contractFunction.estimateGas({from: account}).then((gasAmount) => {
estimatedGas = gasAmount.toString(16);
console.log("Estimated gas: " + estimatedGas);
web3.eth.getTransactionCount(account).then(_nonce => {
nonce = _nonce.toString(16);
console.log("Nonce: " + nonce);
const txParams = {
gasPrice: '0x09184e72a000',
gasLimit: 3000000,
to: contractAddress,
data: functionAbi,
from: account,
nonce: '0x' + nonce
};
const tx = new Tx(txParams);
tx.sign(privateKey);
const serializedTx = tx.serialize();
contract.methods.get().call().then(v => console.log("Value before increment: " + v));
web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).on('receipt', receipt => {
console.log(receipt);
contract.methods.get().call().then(v => console.log("Value after increment: " + v));
})
});
});
结果:
$ npm run my_test
> hello_world_dapp@1.0.0 my_test C:\cygwin\home\adamk\eth\hello_world_dapp
> node ./test.js
Getting gas estimate
Estimated gas: 6919
Nonce: 5
Value before increment: 19
{ transactionHash: '0xb6fdfc36cc32cb01a2be8832a387da586a44a37c1241bbf2979745536f206ed4',
transactionIndex: 0,
blockHash: '0xb6ee8d4e45585010d9a12d48aa37a478eb6021aad78599f1719cb424ab364bb5',
blockNumber: 10,
gasUsed: 26905,
cumulativeGasUsed: 26905,
contractAddress: null,
logs: [],
status: 1 }
Value after increment: 22
以下是用于在rinkeby上发送签名事务的代码段。通过类似的方式,您可以继续ropsten测试网络:
const Tx = require('ethereumjs-tx')
const Web3 = require('web3')
const web3 =new
Web3('https://rinkeby.infura.io/v3/9ce80a86c6c54d22aa821d0486a1a47d')
var account1 = '0xa00c70B72150D627cf53872eefD077079116B6a6'
var account2 = '0xD2a8aa318Fbc56995Db8C415BE6E40329DB1C56C'
const privateKey1 = Buffer.from(process.env.PRIVATE_KEY_1,'hex')
const privateKey2 = Buffer.from(process.env.PRIVATE_KEY_2,'hex')
web3.eth.getTransactionCount(account1,(err,txCount)=>{
const txObject = {
nonce:web3.utils.toHex(txCount),
to:account2,
value:web3.utils.toHex(web3.utils.toWei('0.1','ether')),
gasLimit:web3.utils.toHex(21000),
gasPrice:web3.utils.toHex(web3.utils.toWei('10','gwei')),
}
console.log(txObject)
const tx = new Tx(txObject)
tx.sign(privateKey1)
const serializedTransaction = tx.serialize()
const raw = '0x'+serializedTransaction.toString('hex')
web3.eth.sendSignedTransaction(raw,(err,txHash)=>{
console.log(txHash)
})
})
嘿,亚当,非常感谢!但是,我仍然无法发送带有nonce值的事务。你介意看一看更新后的问题吗?嗯……其他的看起来都是正确的。似乎错误告诉您您的事务计数太大,这似乎很奇怪。
txParams.nonce
的最终值是多少?nonce
的结果类似于21
,我将其转换为十六进制,并在其前面加上0x
仔细检查您的其余逻辑、您的承诺等。我刚刚使用Ganache中的锁定帐户运行了一个类似的示例,效果很好。我将用示例代码、配置和输出更新我的答案。它也可能是您的特定配置,因为它与使用Infura有关,我相信这需要您创建一个令牌并在Truffle中使用特殊配置。看看松露。我建议在与Infura集成之前,先验证您的代码是否在本地工作。Adam,谢谢!它在本地环境中工作正常(使用ganache cli和truffle控制台),但在ropsten中,它挂起并抛出以下内容:事务未在50个块内挖掘,请确保您的事务已正确发送。请注意,它可能仍在开采中代码>能否尝试将提供程序更改为const provider=new Web3.providers.HttpProvider(“https://ropsten.infura.io");
并再次尝试相同的代码?在您的更新中,您已经在TX对象中使用了异步(承诺)代码更新nonce
。该对象只有在相同的then
块中运行时才能看到更新的nonce状态。