用 ethers.js 发送高 gas 的替换交易

本文中,我们将在以太坊测试网上用 ethers.js 重发交易,并介绍相关的术语和知识。

概述

有时,在以太坊上提交的交易没有足够的 gas ,因为网络拥堵或有太多的待处理交易提供了比你的交易报价更高的 gas 价格。如果你有一个高优先级的交易,但由于 gas 不足,可能最终不得不等待数小时甚至数天才能打包结算。在这种情况下,你需要用更高的 gas 价格和相同的 nonce 重新发送交易,以使它尽早被打包。

本文中,我们将在以太坊测试网上用 ethers.js 重发交易,并介绍相关的术语和知识。

什么是以太坊交易?

当我们想在以太坊网络上添加、更新或修改一些内容时,就需要发送一笔交易。基本上,交易是现实世界与以太坊网络互动的方式。每一笔在以太坊网络上交易,都需要支付一笔叫做 gas 的费用。gas 的单位是 wei(ETH的最小单位)或 gwei。

以太坊的交易类型

在以太坊网络中,有三种常见的交易类型:

  1. 普通交易:如把以太币(ETH/ether)从一个账户转移到另一个账户。
  2. 创建合约交易:在以太坊区块链网络上部署智能合约的交易。
  3. 调用合约交易:该交易用于(发送一些数据)与先前部署的智能合约交互。

一个典型的以太坊交易的参数:

  • from: 交易发起地址,20字节的地址,代表发起交易的账户。
  • to:交易目标地址(接收者),20个字节的地址,代表交易向谁发起(或向谁转账)。
  • value: 交易中从一个账户发送至另一个账户的 ETH 数量。
  • data: 对于创建合约,这个字段包含编译为字节码的智能合约代码。对于调用合约,这个字段包含函数签名(函数选择器)和参数 - 标识如何调用智能合约函数,对于普通的资金交易,则留空或是留言信息。
  • gasLimit: 交易中可以作为最大 gas 使用额度。
  • gasPrice:这是发送方愿意为单位 gas 交易支付的金额,以 wei 计价。
  • chainId:交易发送到哪一个以太坊网络,网络ID(主网mainnet:1,rinkeby:4,kovan:42等,可参考以太坊主要网络 chainId 及 NetworkID
  • nonce:它是一个账号发出过的交易计数。每当一个地址发送一笔交易,nonce就会增加1。

以太坊的交易流程

  • 构造一个交易对象,并向其提供所有必要的参数。
  • 用发送者的私钥对交易进行签名。
  • 用以太坊节点将交易发送到以太坊网络中。

对交易进行签名

签署交易是指使用发送者的私钥在交易对象上生成一个签名。如果你想了解更多关于以太坊签名和验证的信息,这里有一些很好的读物:Yos 写 以太坊签名和验证签名和Angello Pozo的 以太坊签名和验证

现在,我们对以太坊的交易有了更好的了解,下面我们自己发一笔交易:

依赖条件:

  • 安装好 NodeJS
  • 一个文本编辑器
  • 终端,又称命令行

安装必要的工具

我们使用 NodeJS 来管理库和处理 javascript 文件。先看看是否安装了 NodeJS ,打开终端并运行:

$ node -v

如果没有安装,可以从官方网站下载 NodeJS 的 LTS 版本。

为了发送交易,我们将使用一段简短的 javascript 代码,以及将使用 ethers.js 库,你可以在命令行终端用 npm 安装它:

$ npm install --save ethers

在这一步最常见的问题是node-gyp的内部故障,可以参考node-gyp安装说明

另一个常见的问题是缓存过期,只需要除 npm 的缓存:

$ npm cache clean

查看ethers.js指南以了解更多关于 ethers.js 库的信息。

创建钱包账号并获得一些测试 ETH

现在,让我们为自己创建一个钱包账号。首先,创建一个 index.js 文件或你要的其他命名的 javascript 文件。然后将下面复制/粘贴到你的代码编辑器中:

var ethers = require('ethers');  
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var wallet = new ethers.Wallet(privateKey);
console.log("Address: " + wallet.address);

稍微解释一下代码:导入之前安装的 ethers.js 库(第1行),为钱包创建一个特定的私钥,它可以是任何数字,并确保它包含与上面(第2行)相同的位数,使用私钥在以太坊创建一个钱包实例(第3行),在控制台打印文字"Address:"及钱包地址(第4行)。

用以下方法运行该文件:

node index.js

如果一切顺利,它应该看起来像这样:

由于每笔交易都需要 gas 费,我们需要一些 gas 在交易中发送,我们可以在钱包中获得一些测试 ETH。为此,我们将使用一个 Kovan 节点,去 Kovan 水龙头获得一些测试 ETH,复制粘贴你运行上述代码得到的钱包地址,然后点击“send me KETH!” 。

注意:这是测试 ETH ,没有市场价值。

启动以太坊节点

对于本文来说,我们可以使用任何以太坊客户端,如 Geth 或 OpenEthereum(之前名为 Parity)。要独自启动一个以太坊节点,首先需要选择一个客户端并对其进行配置;同步一个以太坊节点并维护它是一项具有挑战的任务;同步一个以太坊全节点可能需要几天时间。

这对于仅仅发送一个交易来说有点太过复杂,我们选择 QuikNode 提供的免费节点URL。成功创建免费以太坊节点后,复制提供者地址( HTTP Provider)地址:

本文中使用的是 Kovan 的测试网节点。

你以后会需要使用,请复制它并保存好。

发送和重新发送一个交易

现在,我们有一个钱包地址和一些测试 ETH 。现在,我们发送一个交易,将一些 ETH 转移到另一个钱包地址。首先我们需要在 index.js 文件中添加一些内容,把下面的代码复制/粘贴到代码编辑器中:

var ethers = require('ethers');  
var url = 'ADD_YOUR_ETHEREUM_NODE_URL';
var customHttpProvider = new ethers.providers.JsonRpcProvider(url);
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var wallet = new ethers.Wallet(privateKey);
console.log("Address: " + wallet.address);
tx = {
  to: "0x6E0d01A76C3Cf4288372a29124A26D4353EE51BE",
  value: ethers.utils.parseEther("0.05"),
  chainId: 42,
  nonce: 3
}
customHttpProvider.estimateGas(tx).then(function(estimate) {
    tx.gasLimit = estimate;
    tx.gasPrice = ethers.utils.parseUnits("0.14085197", "gwei");
    wallet.signTransaction(tx).then((signedTX)=>{
    customHttpProvider.sendTransaction(signedTX).then(console.log);
    });
});

然后,用上面一节中的 HTTP 提供者替换ADD_YOUR_ETHEREUM_NODE_URL

简单解释一下上面的代码:(第1行)导入之前安装的 ethers 库,(第2行)设置以太坊节点 URL,(第3行)实例化一个 ethers JsonRpcProvider 实例,(第4行)创建一个特定的钱包的私钥,可以是任何数字,并确保它包含相同位数。(第5行)用私钥创建一个以太坊的钱包实例,(第6行)在控制台中打印钱包地址,(第7-12行)创建一个交易对象并在 to 字段中添加接收者的地址,你也可以用var wallet = Wallet.createRandom();生成一个随机地址,在value字段设置要发送的 ETH 的价值,在chainId字段,因为我们使用的是 Kovan ,设置为42,nonce字段设置为3,(第13-15行)根据节点估计 gasLimit 并设置 gas 价格,(第16-18行)用钱包的私钥为交易签名并发送,同时在控制台打印该交易。

运行一下:

node index.js

我们会得到一个类似这样的输出:

复制hash字段的字符串(类似0xe49c8122656c612bf5f1e10b251f56671acf01d831b6876c37c5a52053035642)并粘贴到Kovan 浏览器的搜索框中,以检查交易的状态。你会看到,该交易尚未被添加到区块链上的新区块中,是等待(pending)状态。这是因为我们设置的 gas 值明显偏低。

现在,我们尝试用相同的 nonce 发送相同的交易,但这次是增加 gas 值;将代码中第15行的gasPrice值从0.14085197改为2.14085197并重新运行代码:

node index.js

复制新输出的ash字段的字符串,并将其粘贴到Kovan 浏览器的搜索框中,再次检查交易的状态。这一次,我们的交易成功被添加到区块中,并且状态为成功,因为我们在发送交易时增加了gasPrice值。

注意:nonce值在两次交易中是相同的。如前所述,nonce 是一个以太坊地址的交易数量。为了重新提交一个有更多 gas 的交易,你必须使用与原始交易相同的nonce。如果你使用增加的 nonce,这将是一个新的交易,那么你的发送 ETH 会比你的想象的更多(因为发送了两次)。

结论

因此,正如我们在上面的例子中看到的,交易的 gas 价格是用于竞争交易优先打包权。区块链上的矿工通常会根据可用的区块空间占有率来设置 gas ,当有一笔交易的 gas 低于阈值 gas 值时,它不会被验证。与其他交易相比,gas 值较高的交易会很快得到验证。


本翻译由 CellETF 赞助支持。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2021-10-21 09:56
  • 阅读 ( 522 )
  • 学分 ( 3 )
  • 分类:以太坊

0 条评论

请先 登录 后评论
aisiji
aisiji

5 篇文章, 769 学分