将离线交易发送到主网是#34; flaky。"

时间:2018-03-07 05:08:31

标签: ethereum

这是我用来以编程方式将签名交易发送到主网的代码:

import Web3 from 'web3'
import EthereumTx from 'ethereumjs-tx'

const web3 = new Web3(new Web3.providers.HttpProvider(INFURA_URL))
const Contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS)

const createItem = (name, price, nonce, callback) => {
  console.log(`Nonce: ${nonce}. Create an Item with Name: ${name}, Price: ${price}`)

  const data = Contract.methods.createItem(name, price).encodeABI()
  const tx = new EthereumTx({
    nonce: nonce,
    gasPrice: web3.utils.toHex(web3.utils.toWei('4', 'gwei')),
    gasLimit: 400000,
    to: CONTRACT_ADDRESS,
    value: 0,
    data: data,
  })

  tx.sign(new Buffer(MAINNET_PRIVATE_KEY, 'hex'))

  const raw = '0x' + tx.serialize().toString('hex')

  web3.eth.sendSignedTransaction(raw, callback)
}

export default createItem

我必须在合同中批量创建(即填充)项目,我想以编程方式进行。但是,虽然代码在ropsten中运行良好,但它无法在mainnet中发送所有事务;它只发送前几个交易而不发送其余交易。错误没有用,因为通常会发生此错误:

Unhandled rejection Error: Transaction was not mined within 50 blocks, please make sure your transaction was properly sent. Be aware that it might still be mined!

我想知道其他人今天必须向以太坊主网发送大量交易时会怎么做。我有什么不对的吗?

1 个答案:

答案 0 :(得分:2)

你基本上不能可靠地做你们想要做的事情。这是一系列问题:

  • 交易仅以现时顺序成功。如果早期的nonce正在等待(或者更糟糕的是,失踪),则另一个事务将暂停,直到早期的nonce被消耗(或者它从mempool中删除)。

  • 当事务从mempool中删除时没有硬性规则。当你因为某些原因发出一个nonce错误或者一个中间nonce没有到达网络时,这是很可怕的,因为你不知道当你最后发布那个nonce时会发生什么。

  • 可以发送许多具有相同nonce的事务。他们很有可能被天然气价格选中(因为矿工被激励去做那个)。发生奇怪事件时,一个有用的技巧就是通过发送一堆高油价,零价值的交易来清除你的随机数。你可以称之为增量方法。请记住,这需要付费。

  • 许多工具可以执行以下两项操作之一来处理nonce:从getTransactionCount()读取实时内容或从getTransactionCount()读取,然后为您发送的每个附加事务递增。这些都不能可靠地工作:首先,交易有时是未决的但在池中不可见。如果天然气价格低于safemin,这似乎特别发生,但我不完全确定这里发生了什么。对于第二个,如果任何其他系统发送具有相同地址的事务,则它将不起作用。

那么,我们如何解决这个问题?

  • 智能合约是将交易从许多发件人随机数减少到少数发件人随机数的简单方法。写一份发送所有不同交易的合同,然后将预算发送给该合同。这是解决问题的相对较高的成本(就时间/精力/专业知识而言)。

  • 无论如何,只需要批处理。当我不得不手动发送许多交易时,我已经将它们分批到10个左右,然后就去了。每次手动递增nonce(因为事务通常不在网络上),然后等待足够长的时间来确认所有事务。不要依赖Etherscan或类似的待处理事务来确定这是否有效,因为事情往往会从这个级别无法预测地消失。永远不要将nonce重用于不是非常高的天然气交易的不同交易 - 你会搞砸它,你最终会错误地发送相同的交易两次​​。

  • 序列化。一个接一个地发布一个事务,等待它确认,增加你的现时。这可能是易于实施的自动化解决方案中最好的。它不会失败。如果您有一个持续的事务流,它可能永远缓冲。它还确保每个块永远不会有多个事务,将吞吐量限制在每分钟4个左右。

  • 点火并重试。这有点粗略,因为它涉及重用不同事务的nonce。将所有(或大批量)交易发送到网络。如果有任何失败,请从失败的nonce重新启动并再次发送。可能有一个更智能的解决方案,你只需要尝试换掉丢失的nonce。您需要非常小心,不要在挂起但不可见的池中秘密发送交易。

  • 每笔交易的新地址。将资金分配到您自己的地址的缓冲步骤可确保您永远不会为其他人搞砸。它会使您的交易时间和成本增加一倍。

我认为火和重试的一些变体是大多数大型服务(如池和交换)所做的。其中一些可以通过将预算分配到几个可用的地址(降低冲突频率)来改进。