交易发送失败常见问题

在发送交易前通常需要调用 estimate 方法获取交易所需的 gas 和 storageLimit 值,然后调用 sendRawTransaction 方法发送交易。因此本章节包含了这两个方法的常见错误

Can not estimate: NotEnoughCash

如果在发送交易时遇到错误:Can not estimate: transaction execution failed, all gas will be charged (execution error: NotEnoughCash { required: xx, got: xx, actual_gas_cost: xx, max_storage_limit_cost: xx }) 则表示交易的 from 账户余额不足。此种情况需要检查是否交易的 gasPrice,gas,storageLimit 设置过大,或者给 from 账号准备足够的余额,或给合约设置代付.

错误详情

此错误是由RPC 方法 cfx_estimateGasAndCollateral 返回(从v2.0.2开始),在调用该方法时,如果参数中设置了 from 信息,会使用 from 账户的真实 balance 来模拟执行交易,如果账户的余额不足以支付交易的 value + gas*gasPrice + storage抵押费,则 estimate 操作将会失败,并返回如下错误:

{
		"code": -32015,
		"message": "Can not estimate: transaction execution failed, all gas will be charged (execution error: NotEnoughCash { required: 18014398509481983999023437515000000, got: 0, actual_gas_cost: 0, max_storage_limit_cost: 18014398509481983999023437500000000 })",
		"data": "0x4e6f74456e6f75676843617368207b2072657175697265643a2031383031343339383530393438313938333939393032333433373531353030303030302c20676f743a20302c2061637475616c5f6761735f636f73743a20302c206d61785f73746f726167655f6c696d69745f636f73743a203138303134333938353039343831393833393939303233343337353030303030303030207d"
}

在 estimate 操作检查 balance 可大大减少 pending 交易。目前 TestNet 公开 RPC 节点已完成升级,cfx_estimateGasAndCollateral 该方法参数的默认值如下:

  1. gasPrice: 1 Drip
  2. gas: 1500w

另外从 v2.0.2 开始,发送交易的最低 gasPrice 提高到了 1GDrip

如何分析余额不足的具体原因

可通过如下步骤检查具体不足原因:

  1. 检查发送账户是否有余额
  2. 如果发送账户有余额,检查是否 gas, gasPrice, storageLimit 设置过大,余额不足有可能是某项设置过大导致的,比如 storageLimit
  3. 如果交易接受账户是一个合约,且合约有 sponsor,检查

注意:可使用 Scan 的赞助页面查看合约的赞助余额,可通过 SponsorWhitelistControl 合约的读写合约功能,查看白名单设置情况

合约设置了赞助商,为什么还是报此错误

用户可能会遇到此种情况:交易的 to 地址是一个合约,且合约已经设置了赞助商,但发送交易时还是报 NotEnoughCash 错误。此种情况可能是由两个原因导致的:

  1. 合约代付的白名单可能没有正确设置,交易的 from 地址不在白名单里,所以代付未生效
  2. 交易的 gasFee(gasPrice * gas) 超过了燃气代付的上限(upperbound), 所以代付未生效

解决办法

解决此错误可使用如下方法之一:

  1. 可尝试在预估燃气费时将 gasPrice 设为 1Drip,得到预估值后发送交易时再把燃气费设为正确的值比如 1GDrip。
  2. 直接升级最新版本的 SDK(js,go,java), 目前最新版本的SDK 已针对此 case 做了处理
  3. 如果条件允许,可提高合约燃气赞助的 upperbound 到 0.05 CFX

Estimation isn't accurate: transaction is reverted

发送交易前通常会调用 cfx_estimateGasAndCollateral 方法,来预估交易执行所需要的 gasstorageLimit。该方法本质是对交易进行了模拟执行,然后统计交易执行完之后实际的 gas 和 storage 使用量。但交易的模拟执行并不是都会成功的,部分交易由于某些原因会执行失败,这时该方法会返回 Estimation isn't accurate: transaction is reverted 错误:

{
		"code": -32015,
		"message": "Estimation isn't accurate: transaction is reverted. Innermost error is at CFX:TYPE.CONTRACT:ACDUZTJBPM9PPP9F0K5VT3PJU0EJUDNHP2ZM7WS35N: Vm reverted. .",
		"data": "CFX:TYPE.CONTRACT:ACDUZTJBPM9PPP9F0K5VT3PJU0EJUDNHP2ZM7WS35N: Vm reverted. \nCFX:TYPE.CONTRACT:ACD5E6SPRGMDVG15FDXF2B8AH7DAN7GMZAGXA10EPZ: Vm reverted. "
}

遇到该错误意味着合约方法代码无法成功执行,交易被 reverted。导致此错误的可能较多,比如:发送合约代币或 NFT 余额不够;合约方法传参错误;没有权限或授权,等等。

如果合约执行时抛出了错误 message,这时 RPC 的错误信息中可以看到合约执行失败的具体原因,比如如下错误是在进行 NFT(1155)转账时,余额不足合约返回的错误:

Estimation isn't accurate: transaction is reverted: ERC1155: insufficient balance for transfer. Innermost error is at xxxx: Vm reverted. ERC1155: insufficient balance for transfer

参考

Can not estimate: transaction execution failed

在调用 estimate 的方法的时候,如果方法执行失败,则会报此错误。Can not estimate: transaction execution failed, all gas will be charged

有时后边可能会包含错误的详情,目前已知的有如下几种:

ConflictAddress(0xxxxx)

{
  "code": -32015,
  "message": "Can not estimate: transaction execution failed, all gas will be charged (execution error: VmError(ConflictAddress(0x87e69792aab04a1e54faa54b41a688335199c1bb)))
",
  "data": "VmError(ConflictAddress(0x87e69792aab04a1e54faa54b41a688335199c1bb))"
}

此错误为合约部署地址冲突错误,意味着部署操作将要部署的合约地址,已经有合约存在。

如果某账户的第一笔交易为合约部署交易,且之后用相同的 data 再次 estimate,且不指定 nonce 的情况,会触发此错误。因为 nonce 的默认值为 0

此时在进行 estimate 时指定 nonce 为用户当前 nonce, 即可解决此问题.

BadInstruction { instruction: 214 })

{
  "code": -32015,
  "message": "Can not estimate: transaction execution failed, all gas will be charged (execution error: VmError(BadInstruction { instruction: 214 }))
",
  "data": "VmError(BadInstruction { instruction: 214 })"
}

此错误表示在部署合约时,传递的 data 数据有问题,包含错误的指令。

一种触发此错误的场景为,在调用合约方法时,未指定合约地址,此时会被认为是创建合约的操作,但 data 数据又不正确,导致此错误.

VmError(OutOfGas)

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32602,
        "message": "Can not estimate: transaction execution failed, all gas will be charged (execution error: VmError(OutOfGas))"
    },
    "id": "15922956697249514502"
}

此错误产生是由于在进行 estimate 操作时指定的 gas 值较小,不足以支撑交易执行完,因此返回了 OutOfGas 错误。这种情况调大 gas 值,或者不传递 gas 字段(自动预估)即可.

另外一种情况是在 estimate 时虽然未指定 gas 值,但还是遇到了 OutOfGas 错误,此种情况说明合约执行逻辑消耗 gas 过大,超过了单 tx 上限,此时需要优化合约的执行逻辑。

SendRawTx: Invalid parameters: tx

发送交易时,如果构造的交易不正确,会遇到 Invalid parameters: tx 错误。错误的具体原因在 RPC 返回数据的 data 字段中, 大致会有如下几种:

余额不足

Transaction {?} is discarded due to out of balance, needs {?} but account balance is {?}

从 conflux-rust v2.0.2 开始 cfx_sendRawTransaction 方法会拒绝掉 tx.from 余额不足以支付交易 value + gasFee + storageCollateral 的交易。

nonce 设置错误

许多交易发送错误是由于 nonce 未设置正确导致的

tx already exist

此错误表示同 nonce 的交易已经存在于交易池中了,重复发送相同的交易会报错

Tx with same nonce already inserted

此错误亦表示同 nonce 交易已经在交易池中

Transaction 0xxx is discarded due to a too stale nonce

此错误表示发送的交易使用了一个已经被执行过交易的 nonce,通俗点说这个 nonce 已经被用过了,不能再使用,需要使用新的未使用的 nonce 重新发送

Transaction 0xxx is discarded due to in too distant future

此错误表示使用了一个过大的 nonce 构造交易,发送交易时 nonce 只能比用 current nonce - current nonce + 2000 范围内的,如果比当前可用 nonce 大超过 2000 会报此错误

gasPrice 错误

ZeroGasPrice

交易的 gasPrice 设置为 0 会报此错误。交易的 gasPrice 必须会大于 0.

transaction gas price 1000000 less than the minimum value 1000000000

从 conflux-rust v2.0.2 开始交易的最低 gasPrice 改为 1GDrip(9个0),如果gasPrice 小余该值,会报此错误

gas 设置错误

交易的 gas 字段设置过大,或过小也会发送失败

NotEnoughBaseGas { required: 21000, got: 2000 }

如果交易的 gas 小余 21000,则会报此错误

transaction gas 20000000 exceeds the maximum value 15000000, the half of pivot block gas limit

如果交易的 gas 超过 1500w 会报此错误

其他参数设置错误

EpochHeightOutOfBound { block_height: 53800739, set: 0, transaction_epoch_bound: 100000 }

交易 epochHeight 字段设置错误,只能设置 10w epoch 以内的区块号

Unsupported receiver address type

交易接受地址填写错误

ChainIdMismatch { expected: 1, got: 2 }

交易的 chainId 填写错误,与发送链的 chainId 不一致

编码签名错误

RlpIncorrectListLen

交易内容不完整,可能会报 Rlp 错误长度错误

Can not recover pubkey for Ethereum like tx

此错误为交易签名错误

网络拥堵

在网络拥堵的情况下,交易池中的交易可能会达到容量上限,此时发送交易可能会遇到以下错误

txpool is full

表示交易池中交易已满

Failed imported to deferred pool: Transaction Pool is full

表示交易池中交易已满

其他

Request rejected due to still in the catch up mode.

发送交易的节点未同步到最新数据,仍处于 catch up 模式,需等同步到最新数据后,才能发送交易

Failed to read account_cache from storage: {}

节点错误

参考

具体的 RPC 返回错误详情可参看 cfx_sendRawTransaction error 文档

JS-SDK: Method not found

如果使用 js-conflux-sdk 发送交易,且交易的 from 账号未添加到 wallet 中的时候,会遇到此错误。此种情况通过如下方式添加账号即可:

conflux.wallet.addPrivatekey("your account private key");