区块链入门(4)Truffle创建项目,编译,及项目部署
上一章的结尾说这一次要讲编写一个智能合约部署到测试网络集群中,并进行交易,但我自己越看越觉得内容挺多的.先讲下truffle的项目创建,编译和部署的问题,然后再做上面说的事情吧. truffle是一套以太坊的开发测试框架, 使用solidity开发语言,类似于javascript. truffle的安装在第一篇文章中已经讲过.下面直接开始进入truffle的使用.
Truffle创建项目
使用truffle可以很简单的创建项目:
mkdir truffle-project
truffle init
这个命令只会创建一个简单的项目,用于编写,编译,部署基于Solidity的只能合约,
如果需要创建基于Web应用的以太坊智能合约,则需要使用:
mkdir truffle-project
truffle init webpack
命令完成以后, 文件夹的目录结构应该是这样:
▾ truffle-project-web-orignal/
▾ app/
▸ javascripts/
▸ stylesheets/
index.html
▾ contracts/
ConvertLib.sol
MetaCoin.sol
Migrations.sol
▾ migrations/
1_initial_migration.js
2_deploy_contracts.js
▸ node_modules/
▾ test/
metacoin.js
TestMetacoin.sol
package.json
README.md
truffle.js
webpack.config.js
目录结构
所有的智能合约都在./contracts目录中,默认情况下,目录中都有一个solidity编写的示例智能合约代码文件和一个示例solidity库文件.它们的扩展名都是".sol".虽然solidity库和智能合约不同,为了更好的说明,我们还是把它们统称为"合约".
编译命令:
编译智能合约只需要运行下面的简单命令:
truffle compile
truffle默认只会编译最后一次编译成功之后被修改过的合约文件, 这是为了减少比必要的编译.设置"--all"选项,可以强制编译所有文件.
编译结果(ARTIFACTS)
编译输出的位置为相对于项目目录的"./build/contracts"目录.如果目录不存在,将会自动被创建.这些编译后的文件完全组成了truffle的内部工作.它们为成功部署你的应用扮演了相当重要的角色.你不应该手动修改这些文件,因为即使修改了, 随着合约的编译和部署,又会被覆盖掉.
依赖项
使用Solidity的"import"命令来申明合约的依赖项. truffle将会自动按照正确的顺序来编译,并保证所有的依赖项都会发送给编译器,依赖可以通过两种方法来指定.
通过依赖项的文件名:
为了从一个独立的文件中导入合约,只需要编写下面的命令, 其中"AnotherContact.sol"文件的路径是相对于当前正在编写的合约的.这将使得"AnotherContact.sol"文件中的所有合约(类)对于当前的源代码都可用.
import "./AnotherContact.sol";
通过导出的包引入合约(类)
truffle支持通过NPM和EthPM安装的依赖库. 要从依赖库中导入合约, 使用下面的语法, "sompackage"表示通过NPM或者EthPM安装的包, "/SomeContract.sol"表示包中提供的solidity源文件的路径(包含文件名).
import "somepackage/SomeContract.sol"
注意:truffle将会先搜索EthPM,然后搜索NPM,所以在低概率情况下,出现了名字的冲突,使用的是EthPM中的库.
部署/迁移
truffle migrate
这条命令将会执行在项目migrations目录中的所有"migrations".最简单的情况是所有的"migrations"只是一个被管理的部署脚本集合.如果执行过"migrations", "truffle migrate"只会启动那些在先前没有执行过的,新创建的"migrations".加入没有新的"migrations"存在,"truffle migrate"不会执行任何任务.可以使用"--reset"选项强制所有"migrations"重新执行.当用于本地测试时,请确保TestRPC已经安装并在执行"migrate"之前运行起来.
迁移文件
一个简单的migration文件看起来是这样:
var MyContract = artifacts.require("MyContract"); module.exports = function(deployer) {
// deployment steps
deployer.deploy(MyContract);
};
请注意文件名有一个数字前缀和一个用于描述的后缀. 编码的前缀是必须的,它需要用来记录"migration"是否执行成功.后缀纯粹是为了便于阅读和理解.
ARTIFACTS.REQUIRE()
在migration文件的开始, 我们通过"artifacts.require()"方法告诉truffle我们将要与那个合约交互.这个方法类似于Node中的"require",但在我们这里,它特殊的返回一个合约抽象,我们可以在后面的部署脚本中使用它这个合约. 这个指定的变量名不是必须与合约源文件的名字相同,但它应该与在源代码中定义的合约类名称相同.考虑下面的示例, 在同一个源文件中定义了两个合约类.
文件名: ./contracts/Contracts.sol contract ContractOne {
// ...
} contract ContractTwo {
// ...
}
如果需要使用"ContractTwo", "artifacts.require()"语句应该是这样:
var ContractTwo = artifacts.require("ContractTwo");
MODULE.EXPORTS(模块导出)
所有"migrations"必须通过"module.exports"语法导出一个函数.每个被"migration"导出的函数都必须有一个"deployer"对象作为函数的第一个参数.这个对象辅助部署时, 为部署智能合约提供了简洁的语法,并担当了一些普通的部署职责,如:保存部署的生成文件为之后的需要使用."deployer"对象是部署阶段的主要接口.其API在本文后面有讲解. "migration"函数还能接受其它的参数.请参考之后的示例.
INITIAL MIGRATION(migration初始化)
truffle为了使用迁移的特性, 需要一个迁移合约.这个合约必须实现指定的接口, 但你可以根据意愿自由的编辑此合约.对于大多数项目来说,这个合约会在第一次迁移的时候就初始部署,并且之后不会再更新.当在使用"truffle init"创建新项目的时候,你默认会得到这个合约. 文件名:contracts/Migrations.sol
pragma solidity ^0.4.8; contract Migrations {
address public owner; // A function with the signature `last_completed_migration()`, returning a uint, is required.
uint public last_completed_migration; modifier restricted() {
if (msg.sender == owner) _;
} function Migrations() {
owner = msg.sender;
} // A function with the signature `setCompleted(uint)` is required.
function setCompleted(uint completed) restricted {
last_completed_migration = completed;
} function upgrade(address new_address) restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
为了能够充分发挥Migrations的特性, 你必须在第一个migration中就部署这份合约.为达此目的,创建下面的"migration":
文件名:migration/1_initial_migration.js
var Migrations = artifacts.require("Migrations"); module.exports = function(deployer) {
// Deploy the Migrations contract as our only task
deployer.deploy(Migrations);
};
从现在开始,你就可以使用增量的数字作为前缀来创建新的migration,用于部署其它的合约, 进行后面的部署步骤了.
DEPLOYER(部署)
"migration"文件将会使用"deployer"来进行部署阶段的任务.因此,你可以按照同步顺序编写部署任务的代码,它们会被按照编写时出现的先后顺序正确执行:
"migration"文件将会使用"deployer"来进行部署阶段的任务.因从,你可以按同步顺序编写部署代码,它们会被按照正确的顺序执行:
// Stage deploying A before B
deployer.deploy(A);
deployer.deploy(B);
或者, deployer上的每个函数可以被用作授权许可, 以按照队列方式进行部署任务, 每个任务都依赖前一个任务的执行结果:
// Deploy A, then deploy B, passing in A's newly deployed address
deployer.deploy(A).then(function() {
return deployer.deploy(B, A.address);
});
你可以把合约的部署编写成一个许可链, 如果你觉得这样的写法会更加清晰的话.
(NETWORK CONSIDERATIONS)网络方面的考虑
可以根据部署的目标网络运行部署方案. 这是一个高级的特性, 所以请先看看"NETWORK(http://truffleframework.com/docs/advanced/networks)"章节,再回来继续. 为了根据条件执行部署步骤, 要求编写的"migrations"接受第二个参数"network".例如:
module.exports = function(deployer, network) {
if (network != "live") {
// Do something specific to the network named "live".
} else {
// Perform a different step otherwise.
}
}
AVAILABLE ACCOUNTS(有效的账户)
在进行部署时, Migrations(迁移)会传递以太坊客户端和web3提供者 提供的账户列表给你使用. 这个列表与"web3.eth.getAccounts()"返回的账户列表完全一样.
DEPLOYER API(部署API)
为了简化"migrations", "deployer"包含许多可用的函数.
DEPLOYER.DEPLOY(CONTRACT, ARGS..., OPTIONS)
这个API,部署一个特定的合约,这个合约由contract对象指定, 具有可选构造参数. 这对单例模式的合约非常有用. 这会在部署后,设置合约的地址(i.e., Contract.address等于新部署的地址), 并会覆盖之前存储的任何地址. 为了快速进行部署多个合约,你可以传合约的数据,或者阵列数组.另外,最后一个参数是一个可选对象"overwrite", 它会观察单个键.如果"overwrite"被设置为 false, 当一个合约已经被部署的情况下, 当前合约就不会被部署. 这对合约地址由外部依赖提供, 这种特定场景是有用的. 需要注意在第一次调用"deploy"之前,你需要部署连接你即将部署的合约的所有依赖库.更多细节, 参考"link"函数.
示例:
// Deploy a single contract without constructor arguments
// 部署单个合约,不带任何构造参数
deployer.deploy(A); // Deploy a single contract with constructor arguments
// 部署单个合约带有构造参数
deployer.deploy(A, arg1, arg2, ...); // Deploy multiple contracts, some with arguments and some without.
// This is quicker than writing three `deployer.deploy()` statements as the deployer
// can perform the deployment as a single batched request.
// 部署多个合约,一些有参数,一些没有参数
// 这比一条"deployer.deploy()"语句部署一个合约快很多.
// 因为deployer可以把所有的合约部署都一次性打包提交.
deployer.deploy([
[A, arg1, arg2, ...],
B,
[C, arg1]
]); // External dependency example:
//
// For this example, our dependency provides an address when we're deploying to the
// live network, but not for any other networks like testing and development.
// When we're deploying to the live network we want it to use that address, but in
// testing and development we need to deploy a version of our own. Instead of writing
// a bunch of conditionals, we can simply use the `overwrite` key.
// 在本示例中, 依赖项提供了一个部署到真实网络中的地址,但没有为相应的测试网络和开发网络提供.
// 当我们部署到真实网络中时,使用这个地址, 但在测试和开发网络的情况下,我们需要部署自己的版本.
// 我们可以用'overwrite'关键字, 代替编写一堆判断条件来执行部署.
deployer.deploy(SomeDependency, {overwrite: false});
DEPLOYER.LINK(LIBRARY, DESTINATIONS)
将一个已经部署好的库链接到一个或多个合约.'destinations'可以是单个合约或者由多个合约构成的数组.如果destinations中的任何合约并没有依赖被链接的库, deployer会忽略这个合约. 例如:
// Deploy library LibA, then link LibA to contract B, then deploy B.
// 部署LibA库, 然后将LibA链接到合约B, 然后再部署B
deployer.deploy(LibA);
deployer.link(LibA, B);
deployer.deploy(B); // Link LibA to many contracts
// 将LibA链接到许多合约
deployer.link(LibA, [B, C, D]);
DEPLOYER.THEN(FUNCTION() {...})
这一段不知道怎么翻译才好, 大家看英语原版吧. 再不明白看示例.
Just like a promise, run an arbitrary deployment step. Use this to call specific contract functions during your migration to add, edit and reorganize contract data. Example:
var a, b;
deployer.then(function() {
// Create a new version of A
return A.new();
}).then(function(instance) {
a = instance;
// Get the deployed instance of B
return B.deployed():
}).then(function(instance) {
b = instance;
// Set the new instance of A's address on B via B's setA() function.
return b.setA(a.address);
});
到这里我们就应该自己能够编写合约的部署代码了.下一次讲什么,等我捋一捋....有点乱.
区块链入门(4)Truffle创建项目,编译,及项目部署的更多相关文章
- 区块链入门(5)Truffle 项目实战,Solidity IDE, 智能合约部署
在上一张我们学习了Truffle项目的创建,部署等相关内容,今天我们就来实战一下. 今天我们要做3件事: 1) 学习搭建一个Solidity IDE(Remix). 2) 使用这个Solidity I ...
- 区块链入门级别认知(blockchain)
区块链入门级别认知(blockchain) 前言:今天参加了迅雷关于区块链的大会,学习和感受总结一下 之前的认知在:几个混迹互联网圈关于区块链 耳熟能详的 热词 “比特币” “区块链” “挖矿” ,知 ...
- 区块链入门到实战(27)之以太坊(Ethereum) – 智能合约开发
智能合约的优点 与传统合同相比,智能合约有一些显著优点: 不需要中间人 费用低 代码就是规则 区块链网络中有多个备份,不用担心丢失 避免人工错误 无需信任,就可履行协议 匿名履行协议 以太坊(Ethe ...
- 区块链入门到实战(38)之Solidity – 条件语句
Solidity支持条件语句,让程序可以根据条件执行不同的操作.条件语句包括: if if...else if...else if 语法 if (条件表达式) { 被执行语句(如果条件为真) } 示例 ...
- 区块链入门到实战(37)之Solidity – 循环语句
与其他语言类似,Solidity语言支持循环结构,Solidity提供以下循环语句. while do ... while for 循环控制语句:break.continue. Solidity – ...
- 区块链入门到实战(36)之Solidity – 运算符
Solidity – 算术运算符 Solidity 支持的算术运算符,如下表所示: 假设变量A的值为10,变量B的值为20. 序号 运算符与描述 1 + (加)求和例: A + B = 30 2 – ...
- 区块链入门到实战(30)之Solidity – 基础语法
一个 Solidity 源文件可以包含任意数量的合约定义.import指令和pragma指令. 让我们从一个简单的 Solidity 源程序开始.下面是一个 Solidity 源文件的例子: prag ...
- 区块链入门到实战(28)之Solidity – 介绍
Solidity语言是一种面向合约的高级编程语言,用于在以太坊区块链网络上实现智能合约.Solidity语言深受c++.Python和JavaScript的影响,针对以太坊(Ethereum)虚拟机( ...
- Apache Maven Cookbook(一)maven 使用命令创建、编译java项目
一.创建 使用命令创建项目分几步: 1.打开命令行窗口,比如cmd,把目录切换至想要创建项目地方. 2.执行如下命令: mvn archetype:generate -DgroupId=com.zua ...
随机推荐
- ionic3使用echarts
1.安装typings及echarts npm install typings echarts --global 2.安装 ECharts 的 TypeScript 定义文件 npm install ...
- Ubuntu14.04安装 ROS 安装步骤和问题总结
参考: 1.http://wiki.ros.org/indigo/Installation/Ubuntu 2.安装出现依赖库问题: https://answers.ros.org/question/3 ...
- python之路——22
学习内容 1.初识面向对象 类:抽象的,模子 对象:具体的,根据类规范 代码精简,修改方便,属性规范2.对象 查看属性 调用方法 __dict__,增删改查,通过字典语法进行3.类名 1.实例化 2. ...
- HTML如何实现斜体字
HTML实现斜体字的标签为<i>标签,用来实现字体倾斜,写法如下: 字体斜体:<i>内容</i> 案例:正常 斜体 当文字加入i标签以后字体就会成为斜体
- docker镜像的常用操作
获取镜像 比如说我们可以这样操作 当然把这个镜像拉过来时间非常长. 查看镜像列表 命令: docker images 说明: 使用docker images命令可以列出本地主机上已有的镜像. 信息 ...
- C# HtmlAgilityPack 爬虫框架
这两天公司不是很忙,在某个网站看见别人爬虫出来的数据感觉很有兴趣就玩了一把,网上找了一个 HtmlAgilityPack 爬虫框架,用了一下感觉很不错 首先从Nuget上面更新Package:Html ...
- Configuring SSL for SAP Host Agent on UNIX
https://help.sap.com/viewer/141cbf7f183242b0ad0964a5195b24e7/114/en-US/8d12f7b9244b44219bd14d619d3a2 ...
- 深入理解Java虚拟机读书笔记1----Java内存区域与HotSpot虚拟机对象
一 Java内存区域与HotSpot虚拟机对象 1 Java技术体系.JDK.JRE? Java技术体系包括: · Java程序设计语言: · 各种硬件平台上的 ...
- 996 icu我能为你做什么?
今天996,未来icu 996icu地址:https://github.com/996icu/996.ICU 前段时间github上出现了,一个讨论996的项目,这个项目使中国的软件工程师达到了空前的 ...
- ThreeJs 模型的缩放、移动、旋转 以及使用鼠标对三维物体的缩放
首先我们创建一个模型对象 var geometry = new THREE.BoxGeometry( 100, 100, 100); //边长100的正方体 var material = new TH ...