在以太坊上部署智能合约和管理交易

在以太坊上构建去中心化应用,如何发送交易、签名并广播到网络。

要在以太坊上构建去中心化应用,你需要知道如何发送交易、签名并广播到网络。通过交易可以转移以太币、部署自己的合约以及与其他智能合约交互。在本教程中,我们将向你演示如何放心地执行这些操作,并介绍一些有助于简化开发工作流的相关代码库和命令。 ## 创建以太坊交易 交易是指在区块链上改变状态的操作。发送以太币、代币以及创建或使用智能合约中的函数都属于交易。如果你对以太坊中的交易还不太熟悉,可查看这些[有关账户、合约以及以太坊交易类型的实用介绍](https://medium.com/@kctheservant/transactions-in-ethereum-e85a73068f74)。 [在本文的代码库中](https://github.com/INFURA/demo-eth-tx),你还将找到一系列脚本,向你演示如何使用下面两种最常用的 Javascript 库与以太坊交互:web3.js 和 ethers.js。有关 web3.js 与 ethers.js 的更多比较信息,请参阅[我们的技术指南,其中详细阐述了两者的相同点和不同点。](https://learnblockchain.cn/article/1851) 流程的第一步是创建交易有效负载(payload)。它的作用是表达你希望执行的操作类型以及你愿意为执行该操作支付多少费用(gas 费)。我们来看看这些属性: **from:20 字节** - 发起交易的地址。 **to:20 字节** - (在创建新合约时可选):接收交易的地址。 **value:数量** - (可选):和该交易一起发送的整数值。 **gas:数量** - (可选,默认:90000) :为执行该交易而提供的汽油整数值。它将返回未用完的汽油。 **gas 价格:数量** - (可选,默认:未定):你愿意为该交易支付的汽油单价整数值(单位:gwei)。 **data:数据** - 对于**合约部署**:编译的合约代码。 - 对于**合约交互**:所调用方法的签名哈希以及编码参数。有关详细信息,请参阅[以太坊合约 ABI](https://learnblockchain.cn/docs/solidity/abi-spec.html)。 - 对于**简单的以太币转账**:“数据”为空。 **nonce:数量** - (可选):nonce 整数值。用户维持交易的处理顺序,并且使你可以使用相同 nonce 覆盖的未处理交易。 作为去中心化应用开发者,你可以依赖于 Web3 实用程序库为你填充其中的大部分详细信息。下面将更加详细地阐述如何根据你需要执行的操作类型来设计这些交易。 ## 对交易签名 生成交易后,你需要对它签名,它才会被以太坊网络所接受。签名有两个作用:1) 证明该交易确实来自你的账户,2) 授权网络从你的账户中扣取交易gas 费。 以太坊交易签名的方式有多种,包括: - 使用具有当地托管私钥的[首选 Web3 库](http://blog.infura.io/ethereum-javascript-libraries-web3-js-vs-ethers-js-part-i/?&utm_source=infurablog&utm_medium=referral&utm_campaign=tutorials&utm_content=tutorial:_deploy_contracts)的签名功能 - 使用单独的签名服务 ([EthSigner](https://docs.ethsigner.pegasys.tech/en/stable/)) - 将该签名过程分派给用户钱包(例如,[Metamask](https://metamask.io/) 或 [Gnosis](https://gnosis.io/)、[Argent](https://www.argent.xyz/)(经由 [WalletConnect](https://walletconnect.org/)) - 使用以太坊节点内置的签名功能 下面提供了不同方法的几个示例: - [在 MetaMask 中如何发送交易](https://docs.metamask.io/guide/sending-transactions.html#example) - [如何使用 NodeJs 创建交易、签名以及在不同账户间发送原始交易](https://medium.com/blockchain-musings/how-to-create-raw-transactions-in-ethereum-part-1-1df91abdba7c) 在大多数案例中,Web3 实用程序库(例如 ethers.js 或 web3.js)通常会获取生成交易并签名的交易,将交易序列化,然后通过 [eth_sendRawTransaction RPC 调用](https://eth.wiki/json-rpc/API#eth_sendrawtransaction)将它发送到节点。 如果你选择使用以太坊节点的内置签名功能,库将使用另一个 RPC 调用 — [`eth_sendTransaction`](https://eth.wiki/json-rpc/API#eth_sendtransaction),将纯文本形式的未签名交易详情发送到节点。Infura **不**支持该交互模式,因此如果你希望使用这种方法,则目前需要有自己托管的节点。需要注意的是,由于该功能要求节点存储私钥并且会使 RPC 暴露在网络上,因此被视为是一种不安全的做法,未经授权访问节点可能会泄露你的私钥,使攻击者能够以你(节点)的名义对交易签名。如果你运行自己的节点,[Hyperledger Besu](https://besu.hyperledger.org/en/stable/) 提供一项非常实用的代理服务 — [EthSigner](https://docs.ethsigner.pegasys.tech/en/stable/),可帮助你对交易签名,将你的密钥安全地存储在单独的文件或密钥库中,并实现 [`eth_sendTransaction`](https://docs.ethsigner.pegasys.tech/en/stable/HowTo/Transactions/Make-Transactions/#eth_sendtransaction) 方法。Ethsigner 可以与任何以太坊客户端一起使用,还支持 Infura。你需要为 Ethsigner 配置[一位签名者](https://docs.ethsigner.pegasys.tech/en/latest/Tutorials/Start-EthSigner/)或[多位签名者](https://docs.ethsigner.pegasys.tech/en/latest/Tutorials/Multifile/),才能[进行交易](https://docs.ethsigner.pegasys.tech/en/stable/HowTo/Transactions/Make-Transactions/)。 ## 使用 Infura 发送以太坊交易 交易签名后,需要将交易广播到以太坊网络,使其他节点可以看到它,矿工可以将它加入到区块链中。 [Infura](https://infura.io/?&utm_source=infurablog&utm_medium=referral&utm_campaign=tutorials&utm_content=tutorial:_deploy_contracts) 提供标准 eth_sendRawTransaction RPC 方法。库通常在后台使用该方法广播交易,因此你无需手动调用 RPC 方法。 在某个时间,以太坊矿工将获得交易副本,完成该交易所在新区块的工作量证明,并将该区块及工作量证明一起广播到整个网络。收到该区块的每个节点都将重新执行包含在其中的交易,并更新以太坊虚拟机 (EVM)* 的状态。 > 注:哪些矿工收到哪些交易、矿工是如何选中这些交易的,以及矿工在完成区块的工作量证明后如何将其广播到网络,这些问题非常复杂。为了简单起见,我们在本教程中不作深入讨论。 ## 以太币转账 以太币转账是最简单的交易形式,因为它是 EVM 原生指令,不需要使用智能合约。我们只需要指定目的地址、Gas价格以及需要发送的以太币值(面值为 wei,1 wei = 1e^18 以太币)。然后对交易签名,这会为它分配 nonce 值和签名。 **示例**:签名并通过一个简单交易发送以太币 **先决条件:**确保已安装 [Node.js](https://nodejs.org/en/) 12+,并且具有可用的 [Infura](https://infura.io/?&utm_source=infurablog&utm_medium=referral&utm_campaign=tutorials&utm_content=tutorial:_deploy_contracts) 项目 ID。复制该资源库并运行: ``` cd demo-eth-tx/ npm install # 在下面添加Infura 项目 ID echo 'INFURA_PROJECT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' > .env ``` 该脚本用于[使用 ethers.js 库](https://github.com/INFURA/demo-eth-tx/blob/master/ethers/send.js)在两个账户之间发送一小笔以太币。运行它并等待矿工挖到交易: ``` node ethers/send.js ``` 相同脚本,[使用 web3.js 库](https://github.com/INFURA/demo-eth-tx/blob/master/web3/send.js)。运行: ``` node web3/send.js ``` ------ ## 智能合约的编译和部署 合约部署是另外一个 EVM 原生操作,与以太币转账看起来几乎相同,但在本情景中,我们将使用 data 参数而不是 to 参数。 我们为 data 传递的实际参数将由我们所部署的合约的字节代码组成。使用 solc 编译器(如果使用 Solidity(首选))可以推导出合约的字节代码。 **注:**当你开始构建自己的智能合约时,可能需要使用开发套件,例如 [*Truffle*](https://learnblockchain.cn/docs/truffle/)、[*Buidler*](https://github.com/nomiclabs/buidler) 或 [*Remix*](https://remix.ethereum.org/)。这些工具将减轻你的工作,因为你无需手动编译智能合约代码。 示例:使用智能合约 现在我们来介绍编写、部署智能合约以及与它交互的必需步骤。 先从简单合约 (Demo.sol) 开始: ```js contract Demo { event Echo(string message); function echo(string calldata message) external { emit Echo(message); } } ``` 该合约有一个函数(名为 echo),任何人都可以使用 message 进行调用。它将触发一个事件,该事件回传输入的 message。 ### 合约编译 在网络上部署合约之前,我们需要先编译合约。这里包含一个简单的 compile.js 脚本可用于此目的: ``` node compile.js ``` 编译合约后,在主目录中将显示一个 Demo.json 文件。该文件包括合约字节代码(在部署时必须使用)以及合约交互所必需的应用程序二进制接口 (ABI)。 ### 合约部署 下面这些部署脚本对 [ethers.js](https://github.com/INFURA/demo-eth-tx/blob/master/ethers/deploy.js) 和 [web3.js](https://github.com/INFURA/demo-eth-tx/blob/master/web3/deploy.js) 均适用。运行其中的任何脚本都可以部署合约: ``` node ethers/deploy.js # 或 node web3/deploy.js ``` 部署合约后,你将收到交易哈希。你可以使用区块浏览器或 `getTransaction()` 和 `eth.getTransactionReceipt()` 进行检查。矿工挖到部署交易后,脚本将输出新合约的地址。 ### 合约交互 部署合约后,你可以与合约交互。你需要通过将合约地址传递到 `to` 参数,并传递一些数据告诉合约如何执行 `data` 参数,来执行交易。 Web3 实用程序库为你提供用于签发合约的高层接口,并且为你生成 data 参数。 下面简单解释这些库的背后操作:data 字段的第一部分是与所调用的合约方法关联的[函数选择器](https://solidity.readthedocs.io/en/v0.5.3/abi-spec.html#function-selector)。我们可以通过获得函数名称哈希的前 4 个字节及其括号内的参数类型(删除所有空格)来计算函数选择器。例如,字符串 **transfer(address,uint256)** 可以散列到 4 字节函数签名 0xa9059cbb 中。函数签名与 RLP 编码的函数参数(在本例中为地址和代币数)连接,构成交易 data 字段。有关合约 ABI 规范和参数编码工作的更多信息,请参阅 [Solidity ABI 规范](https://learnblockchain.cn/docs/solidity/abi-spec.html)。 下面这些合约交互脚本对 [ethers.js](https://github.com/INFURA/demo-eth-tx/blob/master/ethers/call.js) 和 [web3.js](https://github.com/INFURA/demo-eth-tx/blob/master/web3/call.js) 均适用。这些脚本配置为与已有的合约交互,但你可以编辑 ethers/call.js 的[这一行](https://github.com/INFURA/demo-eth-tx/blob/master/ethers/call.js#L23)或 web3/call.js 的[这一行](https://github.com/INFURA/demo-eth-tx/blob/master/web3/call.js#L25),然后将其替换为你部署合约的地址。 你现在可以运行: ``` node ethers/call.js # or node web3/call.js ``` 恭喜!你已经部署了以太坊智能合约并和它交互。你现在可以继续构建一些精彩内容! ------ [Infura](https://infura.io/?&utm_source=infurablog&utm_medium=referral&utm_campaign=tutorials&utm_content=tutorial:_deploy_contracts) 为开发者提供对以太坊和 IPFS 网络的快速可靠访问。我们提供[免费核心服务](https://infura.io/register?&utm_source=infurablog&utm_medium=referral&utm_campaign=tutorials&utm_content=tutorial:_deploy_contracts)以及开发者构建去中心化应用所需的一切工具和资源。 衷心感谢 *Lucian Boca* 对本指南的编写做出的广泛贡献。有关更多 *Web3* 教程。

要在以太坊上构建去中心化应用,你需要知道如何发送交易、签名并广播到网络。通过交易可以转移以太币、部署自己的合约以及与其他智能合约交互。在本教程中,我们将向你演示如何放心地执行这些操作,并介绍一些有助于简化开发工作流的相关代码库和命令。

创建以太坊交易

交易是指在区块链上改变状态的操作。发送以太币、代币以及创建或使用智能合约中的函数都属于交易。如果你对以太坊中的交易还不太熟悉,可查看这些有关账户、合约以及以太坊交易类型的实用介绍。

在本文的代码库中,你还将找到一系列脚本,向你演示如何使用下面两种最常用的 Javascript 库与以太坊交互:web3.js 和 ethers.js。有关 web3.js 与 ethers.js 的更多比较信息,请参阅我们的技术指南,其中详细阐述了两者的相同点和不同点。

流程的第一步是创建交易有效负载(payload)。它的作用是表达你希望执行的操作类型以及你愿意为执行该操作支付多少费用(gas 费)。我们来看看这些属性:

from:20 字节

  • 发起交易的地址。

to:20 字节

  • (在创建新合约时可选):接收交易的地址。

value:数量

  • (可选):和该交易一起发送的整数值。

gas:数量

  • (可选,默认:90000) :为执行该交易而提供的汽油整数值。它将返回未用完的汽油。

gas 价格:数量

  • (可选,默认:未定):你愿意为该交易支付的汽油单价整数值(单位:gwei)。

data:数据

  • 对于合约部署:编译的合约代码。
  • 对于合约交互:所调用方法的签名哈希以及编码参数。有关详细信息,请参阅以太坊合约 ABI。
  • 对于简单的以太币转账:“数据”为空。

nonce:数量

  • (可选):nonce 整数值。用户维持交易的处理顺序,并且使你可以使用相同 nonce 覆盖的未处理交易。

作为去中心化应用开发者,你可以依赖于 Web3 实用程序库为你填充其中的大部分详细信息。下面将更加详细地阐述如何根据你需要执行的操作类型来设计这些交易。

对交易签名

生成交易后,你需要对它签名,它才会被以太坊网络所接受。签名有两个作用:1) 证明该交易确实来自你的账户,2) 授权网络从你的账户中扣取交易gas 费。

以太坊交易签名的方式有多种,包括:

  • 使用具有当地托管私钥的首选 Web3 库的签名功能
  • 使用单独的签名服务 (EthSigner)
  • 将该签名过程分派给用户钱包(例如,Metamask 或 Gnosis、Argent(经由 WalletConnect)
  • 使用以太坊节点内置的签名功能

下面提供了不同方法的几个示例:

  • 在 MetaMask 中如何发送交易
  • 如何使用 NodeJs 创建交易、签名以及在不同账户间发送原始交易

在大多数案例中,Web3 实用程序库(例如 ethers.js 或 web3.js)通常会获取生成交易并签名的交易,将交易序列化,然后通过 eth_sendRawTransaction RPC 调用将它发送到节点。

如果你选择使用以太坊节点的内置签名功能,库将使用另一个 RPC 调用 — eth_sendTransaction,将纯文本形式的未签名交易详情发送到节点。Infura 支持该交互模式,因此如果你希望使用这种方法,则目前需要有自己托管的节点。需要注意的是,由于该功能要求节点存储私钥并且会使 RPC 暴露在网络上,因此被视为是一种不安全的做法,未经授权访问节点可能会泄露你的私钥,使攻击者能够以你(节点)的名义对交易签名。如果你运行自己的节点,Hyperledger Besu 提供一项非常实用的代理服务 — EthSigner,可帮助你对交易签名,将你的密钥安全地存储在单独的文件或密钥库中,并实现 eth_sendTransaction 方法。Ethsigner 可以与任何以太坊客户端一起使用,还支持 Infura。你需要为 Ethsigner 配置一位签名者或多位签名者,才能进行交易。

使用 Infura 发送以太坊交易

交易签名后,需要将交易广播到以太坊网络,使其他节点可以看到它,矿工可以将它加入到区块链中。

Infura 提供标准 eth_sendRawTransaction RPC 方法。库通常在后台使用该方法广播交易,因此你无需手动调用 RPC 方法。

在某个时间,以太坊矿工将获得交易副本,完成该交易所在新区块的工作量证明,并将该区块及工作量证明一起广播到整个网络。收到该区块的每个节点都将重新执行包含在其中的交易,并更新以太坊虚拟机 (EVM)* 的状态。

注:哪些矿工收到哪些交易、矿工是如何选中这些交易的,以及矿工在完成区块的工作量证明后如何将其广播到网络,这些问题非常复杂。为了简单起见,我们在本教程中不作深入讨论。

以太币转账

以太币转账是最简单的交易形式,因为它是 EVM 原生指令,不需要使用智能合约。我们只需要指定目的地址、Gas价格以及需要发送的以太币值(面值为 wei,1 wei = 1e^18 以太币)。然后对交易签名,这会为它分配 nonce 值和签名。

示例:签名并通过一个简单交易发送以太币

先决条件:确保已安装 Node.js 12+,并且具有可用的 Infura 项目 ID。复制该资源库并运行:

cd demo-eth-tx/
npm install
# 在下面添加Infura 项目 ID 
echo 'INFURA_PROJECT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' > .env

该脚本用于使用 ethers.js 库在两个账户之间发送一小笔以太币。运行它并等待矿工挖到交易:

node ethers/send.js

相同脚本,使用 web3.js 库。运行:

node web3/send.js

智能合约的编译和部署

合约部署是另外一个 EVM 原生操作,与以太币转账看起来几乎相同,但在本情景中,我们将使用 data 参数而不是 to 参数。

我们为 data 传递的实际参数将由我们所部署的合约的字节代码组成。使用 solc 编译器(如果使用 Solidity(首选))可以推导出合约的字节代码。

注:当你开始构建自己的智能合约时,可能需要使用开发套件,例如 TruffleBuidlerRemix。这些工具将减轻你的工作,因为你无需手动编译智能合约代码。

示例:使用智能合约

现在我们来介绍编写、部署智能合约以及与它交互的必需步骤。

先从简单合约 (Demo.sol) 开始:

contract Demo {
    event Echo(string message);

    function echo(string calldata message) external {
        emit Echo(message);
    }
}

该合约有一个函数(名为 echo),任何人都可以使用 message 进行调用。它将触发一个事件,该事件回传输入的 message。

合约编译

在网络上部署合约之前,我们需要先编译合约。这里包含一个简单的 compile.js 脚本可用于此目的:

node compile.js

编译合约后,在主目录中将显示一个 Demo.json 文件。该文件包括合约字节代码(在部署时必须使用)以及合约交互所必需的应用程序二进制接口 (ABI)。

合约部署

下面这些部署脚本对 ethers.js 和 web3.js 均适用。运行其中的任何脚本都可以部署合约:

node ethers/deploy.js
# 或
node web3/deploy.js

部署合约后,你将收到交易哈希。你可以使用区块浏览器或 getTransaction()eth.getTransactionReceipt() 进行检查。矿工挖到部署交易后,脚本将输出新合约的地址。

合约交互

部署合约后,你可以与合约交互。你需要通过将合约地址传递到 to 参数,并传递一些数据告诉合约如何执行 data 参数,来执行交易。

Web3 实用程序库为你提供用于签发合约的高层接口,并且为你生成 data 参数。

下面简单解释这些库的背后操作:data 字段的第一部分是与所调用的合约方法关联的函数选择器。我们可以通过获得函数名称哈希的前 4 个字节及其括号内的参数类型(删除所有空格)来计算函数选择器。例如,字符串 transfer(address,uint256) 可以散列到 4 字节函数签名 0xa9059cbb 中。函数签名与 RLP 编码的函数参数(在本例中为地址和代币数)连接,构成交易 data 字段。有关合约 ABI 规范和参数编码工作的更多信息,请参阅 Solidity ABI 规范。

下面这些合约交互脚本对 ethers.js 和 web3.js 均适用。这些脚本配置为与已有的合约交互,但你可以编辑 ethers/call.js 的这一行或 web3/call.js 的这一行,然后将其替换为你部署合约的地址。

你现在可以运行:

node ethers/call.js
# or
node web3/call.js

恭喜!你已经部署了以太坊智能合约并和它交互。你现在可以继续构建一些精彩内容!

Infura 为开发者提供对以太坊和 IPFS 网络的快速可靠访问。我们提供免费核心服务以及开发者构建去中心化应用所需的一切工具和资源。

衷心感谢 Lucian Boca 对本指南的编写做出的广泛贡献。有关更多 Web3 教程。

区块链技术网。

  • 发表于 2020-12-07 22:23
  • 阅读 ( 1541 )
  • 学分 ( 23 )
  • 分类:DApp

评论