Ethereum入门了解
本文参考Microsoft使用 Solidity 编写 Ethereum 智能合同。
用于处理智能合同的工具
许多工具都可帮助快速高效地开发智能合同。以下各节介绍了一些集成开发环境 (IDE)、扩展和框架。
IDE
- Visual Studio Code:此代码编辑器已经过重新定义和优化,专门用于生成和调试现代Web和云应用程序。
- Remix:一种基于浏览器的编译器和IDE,可以通过它来使用Solidity生成Ethereum合同,使用它来编写、测试和部署自己的合同,并调试交易。
扩展
- Ethereum的区块链开发工具包:此扩展可以简化在Ethereum账本上创建、生成和部署智能合同的方式。
框架
- Truffle 套件:在将Ethereum合同部署到公共账本并产生实际成本之前,使用Truffle工具套件对其进行测试。开发人员可在本地进行开发以便于其工作。
- 该工具套件包括Truffle、Ganache和Drizzle。
- OpenZeppelin:使用OpenZeppelin工具编写、部署和操作去中心化应用程序。
- OpenZeppelin提供了两个产品:合同库和SDK。
安装扩展
在Visual Studio Code的左侧边栏中,选择“扩展”。搜索“区块链开发工具包”,然后选择它进行安装。
使用区块链开发工具包之前,请确保已安装:
- Python:大多数计算机都预先安装了Python。
- Node.js:若要确认已安装Node.js,请打开终端并键入node或npm(node包管理器)。如果安装了Node.js,终端将返回计算机上的Node.js的版本或npm命令列表。
- Git:若要确认已安装Git,请打开终端并键入git。 如果安装了Git,终端将返回可用的Git命令的列表。
- Truffle套件:该扩展提供了一个安装开发人员工具Truffle套件的链接(在扩展处于公共预览阶段时需要)。 (在扩展里面搜Truffle for Vs code)
- (关于Truffle的介绍看这里Truffle - 以太坊Solidity编程语言开发框架)
- Ganache CLI:该扩展提供了一个安装Ganache CLI的链接(在扩展处于公共预览阶段时需要)。
- (实际上这个链接我并没有在扩展里面找到😓,于是另外在网上找了一个介绍Ganache的网站Nethereum Documentation)
如果尚未安装此软件,或者未具有其最低版本,扩展会提供关于如何安装这些工具的提示。
入门
- 如果已安装所有依赖项,请使用区块链开发工具包创建第一个项目:
- 在计算机上,为项目添加一个空目录。若要从Visual Studio Code中创建目录,请依次转到Terminal > New Terminal,然后键入mkdir newSolidityProject,记下这个新目录的位置,稍后需要用到此信息。
- 在Visual Studio Code中,依次打开View > Command Palette。在搜索框中,键入“Blockchain: New Solidity Project”。键入时,将显示一个建议列表。
- 对于Solidity项目类型,选择“创建基本项目”。
- 使用"explorer"窗格查找在步骤 1 中创建的文件夹。选择该文件夹,在窗口的右下角,可以看到"creating a new project"。
创建Solidity项目后,打开"explorer"窗格以查看该项目的文件。
该项目包含 Solidity 代码样板,请注意以下目录:
- 合同:包含 HelloBlockchain.sol 合同和 Migrations.sol 合同
- 迁移:包含初始迁移和部署的合同
- 测试:包含以 JavaScript 编写的对 HelloBlockchain合约的测试
你还会看到下面的配置文件:
- package.json:定义项目详细信息和依赖项
- truffle-config.json:定义Truffle的依赖项和配置
- 若要保存工作区,请转到File > Save Workspace。将其命名为newSolidityProject。
编译合同
首先将从"contracts"文件夹内的HelloBlockchain.sol智能合同开始。
- 在"explorer"窗格中的"contracts"文件夹中,右键单击合同名称HelloBlockchain。
- 选择“生成合同”以编译智能合同。右下角的窗口会指示合同正在生成。
- 选择View > Output以查看所编译的合同的相关信息。在此窗口中,可能需要选择“Azure 区块链”才能查看此扩展的输出。
部署合同
成功编译合同后,可以在本地部署它。 此步骤需要登录 Azure 帐户。
- 在"explorer"窗格中,转到"contracts"文件夹,右键单击合同名称HelloBlockchain。
- 选择“部署合同”。
- 在显示的窗口中,选择“开发”。 如果你还未登录,系统将提示你登录。
在“输出”窗口(位于View > Output)中,将看到所部署的迁移和合同的相关信息。
可在此处查看所部署的合同的以下关键信息或元数据:
- 合同的地址。
- 合同创建交易所属的程序块的时间戳。
- 部署合同的帐户地址。
- 交易后帐户的余额(以以太币为单位)。余额为100个以太币(初始默认值)减去总成本。
- 使用的gas量和gas价格。"gas"指在Ethereum区块链平台上执行交易或执行合同所需的费用。可以将它视为汽车所需的汽油。总成本=gas价格*gas使用量。
- gas价格以gwei表示。1 gwei等价于0.000000001个以太币。
安装Truffle
Truffle是最常用的Ethereum开发框架。可以使用节点包管理器(NPM)安装它。
关于Truffle
Truffle具有以下好处:
- 可生成、编译、部署和测试智能合同
- 可管理网络,从而部署到公共和专用网络
- 可管理项目依赖项的包
- 具有交互式控制台,可直接进行合同通信和管理
- 生成管道可配置,可自动运行检查和配置项目
安装Truffle
可以使用节点包管理器安装Truffle。在终端中键入以下内容:
npm install -g truffle
若要确认已安装 Truffle,请键入以下内容:
truffle
输出会显示已安装的版本,并显示可用于Truffle的命令列表:
Truffle入门
- 在Visual Studio Code中,依次转到Terminal> New Terminal。
- 在终端中运行 truffle compile。等待源文件编译成功。
- 运行truffle migrate。等待迁移完成。
测试合同
下一步来运行在newSolidityProject中生成的测试。
可在test/HelloBlockchain.js中找到此测试。查看测试文件,尝试了解要测试的内容。
在终端中键入truffle test。
测试失败,因为Truffle无法连接到Ethereum客户端:
Could not connect to your Ethereum client with the following parameters:
- host > 127.0.0.1
- port > 8545
- network_id > *
Please check that your Ethereum client:
- is running
- is accepting RPC connections (i.e., "--rpc" option is used in geth)
- is accessible over the network
- is properly configured in your Truffle configuration file (truffle-config.js)
此输出指示你需要一个处于运行状态的本地Ethereum区块链客户端,以便测试可以访问它。
Ganache CLI
Ganache是最常用的本地Ethereum区块链。我们将使用CLI版本,以便可以直接从终端与它交互。Ganache CLI常用于开发和测试。
若要在项目中安装Ganache CLI,请进入终端。右键单击,然后选择New Terminal。当“新终端”窗口打开时,运行以下内容:
npm install -g ganache-cli
安装 Ganache CLI 后,运行以下内容:
ganache-cli
请注意,区块链有10个已生成的帐户,每个帐户会收到100个测试以太币以便于使用。每个帐户还具有相应的私钥,同时也具有助记键。助记键是由12个单词构成的唯一短语,可通过它访问钱包,进而从帐户实现交易。
输出还会显示区块链的地址。我们将使用此地址连接到区块链。默认情况下,该地址为 127.0.0.1:8545。
现在重新运行 truffle test。
在终端中,可以看到所有测试都已通过。
使用Ethereum的区块链开发工具包编写智能合同
向前面创建的newSolidityProject添加新的智能合同。
创建装运合同
将创建的智能合同用于跟踪从在线市场购买的商品的状态。创建该合同时,装运状态设置为Pending。装运商品后,则将装运状态设置为Shipped并会发出事件。交货后则将商品的装运状态设置为 Delivered,并发出另一个事件。
在所创建项目的"contracts"目录中,右键单击该文件夹,然后选择新建名为Shipping.sol的文件。
复制以下合同内容,并将其粘贴到新文件中。
pragma solidity >=0.5.12<=0.8.0;
contract Shipping
{
// Our predefined values for shipping listed as enums
enum ShippingStatus { Pending, Shipped, Delivered }
// Save enum ShippingStatus in variable status
ShippingStatus private status;
// Event to launch when package has arrived
event LogNewAlert(string description);
// This initializes our contract state (sets enum to Pending once the program starts)
constructor() public {
status = ShippingStatus.Pending;
}
// Function to change to Shipped
function Shipped() public {
status = ShippingStatus.Shipped;
emit LogNewAlert("Your package has been shipped");
}
// Function to change to Delivered
function Delivered() public {
status = ShippingStatus.Delivered;
emit LogNewAlert("Your package has arrived");
}
// Function to get the status of the shipping
function getStatus(ShippingStatus _status) internal pure returns (string memory) {
// Check the current status and return the correct name
if (ShippingStatus.Pending == _status) return "Pending";
if (ShippingStatus.Shipped == _status) return "Shipped";
if (ShippingStatus.Delivered == _status) return "Delivered";
}
// Get status of your shipped item
function Status() public view returns (string memory) {
ShippingStatus _status = status;
return getStatus(_status);
}
}
查看该合同,以查看要发生的情况,确认你可以成功生成该合同。
在"Explorer"窗格中,右键单击该合同名称,然后选择“生成合同”以编译该智能合同。
添加迁移
现在我们将添加一个迁移文件,以便我们可以将该合同部署到Ethereum网络。
在"Explorer"窗格中,将鼠标悬停在"migration"文件夹上,然后选择“新建文件”。 将该文件命名为3_deploy_contracts.js。
将以下代码添加到该文件:
const Shipping = artifacts.require("Shipping");
module.exports = function (deployer) {
deployer.deploy(Shipping);
};
部署
接下来要确保可以成功部署该合同,然后再继续。右键单击合同名称,然后选择“部署合同”。在显示的窗口中,选择“开发”,然后等待部署完成。
查看“输出”窗口中的信息。查找3_deploy_contracts.js部署。
测试智能合同
在此部分中,我们将为装运合同编写新的JavaScript测试。我们可以改用Solidity来编写测试,但JavaScript更为常用。我们将使用Truffle测试智能合同。
开始测试
首先我们创建一个新的测试文件。
- 转到“终端”>“新终端”。
- 在新终端中键入 truffle create test Shipping。 这将在测试文件夹中创建一个名为 Shipping.js 的新文件。
- 粘贴下面的代码,以替换该文件中的代码:
const ShippingStatus= artifacts.require("Shipping");
contract('Shipping', () => {
it("should return the status Pending", async ()=> {
// Instance of our deployed contract
const instance = await ShippingStatus.deployed();
// Checking the initial status in our contract
const status = await instance.Status();
// Checking if the status is initially Pending as set in the constructor
assert.equal(status, "Pending");
});
it("should return the status Shipped", async ()=> {
// Instance of our deployed contract
const instance = await ShippingStatus.deployed();
// Calling the Shipped() function
await instance.Shipped();
// Checking the initial status in our contract
const status = await instance.Status();
// Checking if the status is Shipped
assert.equal(status, "Shipped");
});
it("should return the status Delivered", async ()=> {
// Instance of our deployed contract
const instance = await ShippingStatus.deployed();
// Calling the Shipped() function
await instance.Delivered();
// Checking the initial status in our contract
const status = await instance.Status();
// Checking if the status is Delivered
assert.equal(status, "Delivered");
});
});
事件测试
我们将使用truffle断言包来测试合同中发送的事件。通过使用此包,我们可以断言交易过程中发出了事件。
- 在终端中,通过键入npm install truffle-assertions安装此库。
- 请求ShippingStatus合同后,将以下代码添加到测试文件的第2行:
const truffleAssert = require('truffle-assertions');
- 添加一个测试,以确认事件会返回所需的说明。 将此测试放在文件的最后一个测试之后。 在最后一行的一组右大括号的正前方创建新行,在其中添加此测试。
it('should return correct event description', async()=>{
// Instance of our deployed contract
const instance = await ShippingStatus.deployed();
// Calling the Delivered() function
const delivered = await instance.Delivered();
// Check event description is correct
truffleAssert.eventEmitted(delivered, 'LogNewAlert', (event) =>{
return event.description == 'Your package has arrived';
});
});
使用async/await
.deployed() 数会返回一个承诺。因此我们在此函数的前面使用await,并在测试代码的前面使用async。此设置意味着,在部署合同后,直到承诺完成后才能继续进行测试。
此模式常用于测试,因为几乎所有智能合同交易都是异步交易。由于需要先对交易进行验证或挖掘才能将其添加到区块链账本中,因此它们是异步交易。
总之,应以对合同进行全面测试为目标,尤其是计划部署到主要的Ethereum网络(主网)时。
运行测试
在终端中键入以下内容:
truffle test
应该看到所有测试都成功通过:
Contract: HelloBlockchain
✓ testing ResponseMessage of HelloBlockchain
✓ testing Responder of HelloBlockchain
✓ testing RequestMessage of HelloBlockchain
✓ testing State of HelloBlockchain
✓ testing Requestor of HelloBlockchain
✓ testing SendRequest of HelloBlockchain (51ms)
✓ testing SendResponse of HelloBlockchain (46ms)
Contract: Shipping
✓ should return the status Pending
✓ should return the status Shipped (59ms)
✓ should return the status Delivered (58ms)
✓ should return correct event description (39ms)