Ethereum 将已签名的事务发送到Ropsten

Ethereum 将已签名的事务发送到Ropsten,ethereum,web3js,Ethereum,Web3js,使用web3js调用不需要签名的函数很容易(例如,不更新合同状态的函数)。然而,除了手动解锁我的MetaMask钱包和在环境中调用函数之外,还不清楚如何调用需要签名的函数 在第一次将我的dapp部署到Ropsten之后,我需要调用createItem(字符串名称,uint价格)100次来填充items数组。因为我不想在混音中手动操作,所以我想写一个自动操作的脚本 除了web3js之外,我还需要ethereumjs-tx以编程方式签署事务,而无需使用MetaMask。我还需要有我的帐户和私钥。根据

使用web3js调用不需要签名的函数很容易(例如,不更新合同状态的函数)。然而,除了手动解锁我的MetaMask钱包和在环境中调用函数之外,还不清楚如何调用需要签名的函数

在第一次将我的dapp部署到Ropsten之后,我需要调用
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
以下是我的问题:

  • 这通常是做我想做的事情的正确方法吗
  • 如果1为true,如何获取已部署合约的
    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状态。