区块链100讲:Truffle——一个更简单的部署智能合约的方法

【区块链】Truffle 部署和测试 Truffle 部署和测试本文主要参考:here 和 here,因为参考的这篇文章版本有些旧了,所以是根据比较新的版本写的。一、合约部署1、 首先初始化环境truffle init2、开启testrpctestrpc //另开窗口3、部署合约a. 编写合约代码,保存到contracts/YourContractName.sol文件例如:Conference.sol pragma solidity 阅读详情

image

本期《区块链100讲》我们将介绍一个更简单的部署智能合约的方法:Truffle。

1

什么是Truffle ?

Truffle是针对基于以太坊的Solidity语言的一套开发框架。本身基于Javascript。Truffle为以太坊提供了开发环境、测试框架和资产管道(pipeline),旨在使以太坊开发更容易,使用Truffle你会得到:

内置智能合约编译、链接、部署和二进制字节码管理。

针对快速迭代开发的自动化合约测试。

可脚本化,可扩展的部署和迁移框架。

网络管理,用于部署到任意数量的公共和私有网络。

使用EthPM和NPM进行包安装管理。

用于直接合约通信的交互式控制台。

支持持续集成的可配置构建管道。

外部脚本运行程序可以在Truffle环境中执行脚本。

提供了合约抽象接口,可以直接通过var instance = Storage.deployed();拿到合约对象后,在Javascript中直接操作对应的合约函数。

原理是使用了基于web3.js封装的Ether Pudding工具包。简化开发流程。

提供了控制台,使用框架构建后,可以直接在命令行调用输出结果,可极大方便开发调试。

当开发基于Truffle的应用时,我们推荐使用 EthereumJS TestRPC。它是一个完整的运行在内存中的区块链,仅仅存在于你开发设备上。

它在执行交易时是实时返回的,而不等待默认的出块时间,这样你可以快速验证你新写的代码,当出现错误时,也能即时反馈给你。它同时还是一个支持自动化测试的功能强大的客户端。Truffle充分利用它的特性,能将测试运行时间提速近90%。最好使用TestRPC客户端充分测试后,再使用这些客户端。这些是完整的客户端实现,包括挖矿,网络,区块及交易的处理,Truffle可以在不需要额外配置的情况下发布到这些客户端。

下面我们从一个简单的例子开始了解一下Truffle。

2

安装Truffle

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ npm install -g truffle@3.4.11</pre>

安装完成后执行下面的命令,确保Truffle被正确的安装:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ truffle
Truffle v3.4.11 - a development framework for Ethereum

Usage: truffle <command> [options]

Commands:
init     Initialize new Ethereum project with example contracts and tests
compile   Compile contract source files
migrate   Run migrations to deploy contracts
deploy   (alias for migrate)
build     Execute build pipeline (if configuration present)
test     Run Mocha and Solidity tests
console   Run a console with contract abstractions and commands available
create   Helper to create new contracts, migrations and tests
install   Install a package from the Ethereum Package Registry
publish   Publish a package to the Ethereum Package Registry
networks Show addresses for deployed contracts on each network
watch     Watch filesystem for changes and rebuild the project automatically
serve     Serve the build directory on localhost and watch for changes
exec     Execute a JS module within this Truffle environment
unbox     Unbox Truffle project
version   Show version number and exit

See more at http://truffleframework.com/docs</pre>

3

创建并初始化项目

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ mkdir myproject

$ cd myproject

$ truffle init</pre>

初始化完成后的目录结构如下:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">myproject
├── contracts
│   ├── ConvertLib.sol
│   ├── MetaCoin.sol
│   └── Migrations.sol
├── migrations
│   ├── 1_initial_migration.js
│   └── 2_deploy_contracts.js
├── test
│   ├── TestMetacoin.sol
│   └── metacoin.js
└── truffle.js</pre>

contracts/ - 存放我们编写的合约。

migrations/ - 存放迁移部署脚本。

test/ - 存放合约测试脚本

truffle.js - Truffle的配置文件

truffle init会给我们创建一个名叫MetaCoin的代币应用。我们将这个默认的应用删除,我们将编写自己的合约。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ cd myproject

# 删除代币合约

$ rm contracts/ConvertLib.sol

$ rm contracts/MetaCoin.sol

# 删除迁移脚本

$ rm migrations/2_deploy_contracts.js

# 删除测试脚本

$ rm test/TestMetacoin.sol

$ rm test/metacoin.js</pre>

4

创建合约

接下来我们创建一个我们自己的合约,进入contracts目录,创建Storage.sol合约文件。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ cd contracts/
$ touch Storage.sol</pre>

Storage.sol合约的内容如下:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">pragmasolidity^0.4.8;

contractStorage{

uint256storedData;

functionset(uint256data) {
storedData=data;
}

functionget() constantreturns(uint256) {
returnstoredData;
}
}</pre>

5

编译合约

接下来使用truffle compile命令编译刚刚完成的Storage.sol合约

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ truffle compile

Compiling ./contracts/Migrations.sol...
Compiling ./contracts/Storage.sol...
Writing artifacts to ./build/contracts</pre>

从控制台的输出中,我们可以看到合约编译后的文件(artifacts)会写入./build/contracts目录中,这些合约编译后的文件对于Truffle框架能否正常工作至关重要。请不要手动修改这些文件,因为即使修改了,再次执行编译命令时又会被覆盖掉。

Truffle默认只编译自上次编译后被修改过的合约,目的是为了减少不必要的编译。如果你想编译全部合约 ,可以使用–all选项。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ truffle compile --all</pre>

合约编译完成后,我们需要部署Storage.sol合约,在truffle中部署合约需要用到迁移脚本。下面我们进入migrations目录中为Storage合约创建一个迁移脚本。

6

迁移脚本

迁移脚本是由一些Javascript文件组成,用来帮助你把合约发布到以太坊网络中。之所以需要迁移脚本是因为你的部署需求会随着时间改变。随着你的项目的发展,你可以创建新的迁移脚本把这些变化的合约部署到区块链上。之前你运行的迁移历史记录,会被一个特殊的Migrations.sol合约记录在区块链上,后面将对Migrations.sol合约进行详细介绍。

移脚本的命名规则:文件名以数字开头,一个描述性的后缀结尾。数字前缀是必须的,用于记录移植是否成功。后缀仅是为了提高可读性,以方便理解。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ cd migrations
$ touch 2_storage_migration.js</pre>

文件:2_storage_migration.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varStorage=artifacts.require("Storage");
module.exports=function(deployer) {
 deployer.deploy(Storage);
};</pre>

1. artifacts.require()

在迁移脚本开头,我们通过artifacts.require()方法告诉truffle我们将要与那个合约交互。这个方法类似于NodeJs中的require,但在这里,它返回的是一个合约抽象,我们可以在我们的迁移脚本的其余部分中使用这个合约抽象。artifacts.require()中使用的名字不是必须与合约源文件的文件名相同,相反,它应该与在合约源代码中定义的合约类的名称相同。

2. module .exports

在迁移脚本最后,我们通过module.exports到处一个函数,被迁移脚本导出的函数都应该接受一个 deployer 对象作为其第一个参数。deployer对象中的辅助函数在部署过程中提供了一种清晰的语法,用于部署智能合约,以及执行一些常见的任务,比如把发布后的对象保存下来供以后使用。这个 deployer 对象是部署任务的主接口,它的API在本文后面有讲解。

好了,我们的一切准备工作都做好了,接下来我们就可以把Storage.sol部署到我们的区块链上了,在上一章中我们把智能合约部署到geth私有链中,这次我们将把智能合约部署到Testrpc环境中。

如果你还没有安装Testrpc 那么先执行下面的安装命令:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ npm install -g ethereumjs-testrpc</pre>

启动testrpc

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ testrpc

EthereumJS TestRPC v4.0.1 (ganache-core: 1.0.1)

Available Accounts
==================
(0) 0x9d02c028e7dd237213bd181cdb55f98da9ed8e64
(1) 0x0d157f5d9da61893093ba39fad87d08e6c55fc41
(2) 0xd69f903709b80f4ff9b338c725135ff8b7a55b94
(3) 0x5174fb1b516e75428cc1c9fa62e6df3b8313d280
(4) 0xafa676d65111e5ea1790981ca7ccbcf4e1fd37c2
(5) 0x454f7d978cdc588b0932614e512d8570b376aa17
(6) 0x4f8bd67351a54785534133a4b299e4fe402b3438
(7) 0x02d039305aa3628ab7f0cff7f9d7e4e90ff2a331
(8) 0xeace265c6f9153b66e2ce49a34d7a8f39a9223f1
(9) 0xcf396939dc0e067c0c95b5e11808903de62aa11a

Private Keys
==================
(0) 95b6dac199323d4246ce8f13277b85fa94918b17f1271f1b3bee9a2b8e653118
(1) 3567fe613afe8e122cc785b8331907fd21e050eb3144203576d58d37026c9f21
(2) 67eacb4cf7ef07171443e29101cfcb369f7bee2b1ae4c6145c20719e88e7458d
(3) e6ea7cbbcb4e4014738dcdb093f0a8be9fee67c189e18e5f1baf384e05cbe525
(4) b151fbd620ee6a7fea833c8017b181a431d49a9c7e2a777d1ba5e6127b39f909
(5) 6765223734c785fbedce37e16786f7ab79fdd697933e27b4663bd72e5dd29b01
(6) 2d3ade35f2ecec67834fa2b08ab8935d0b4d8b704c41cef8ced9fa24475d7ee4
(7) 385edb489851649f6200621b4338121a7eebead8c05d5f50c036da59b8695a9a
(8) a412e30d941f9015d58bf27f335e90639e1b67cea9c3442ff64dbec58733ba04
(9) e0fd135471034fb5b2e6f494ad3947be012f15d2d08f26985f9bcc52e47e003f

HD Wallet

Mnemonic:     million remember shell basket verify because image mobile extra novel rival purchase
Base HD Path: m/44'/60'/0'/0/{account_index}

Listening on localhost:8545</pre>

testrpc启动成功后,回到myproject项目的目录中,执行迁移命令

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ truffle migrate

Using network 'development'.

Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x9660bd2dad09d2417ab2d0d7931395d4425c857e09dca4cba37850229ea12004
Migrations: 0xe78a0f7e598cc8b0bb87894b0f60dd2a88d6a8ab
Saving successful migration to network...
... 0xbb4949bdd34ff8085babe7e8624b67834f79b8d287b131c79000be7163697932
Saving artifacts...
Running migration: 2_deploy_Storage.js
Deploying Storage...
... 0x33448d46fd119b46b9a49ba6550becee7266f9f02ad48561afca93bf4e13e912
Storage: 0xcfeb869f69431e42cdb54a4f4f105c19c080a601
Saving successful migration to network...
... 0x8e1f6cf2cf9221b6242de54995c6e71e0ae69781a6b4b587a98e3b3ae5acd047
Saving artifacts...
</pre>

truffle migrate命令会执行所有的位于migrations目录内所有的迁移脚本。如果你之前已成功执行过迁移脚本,那么truffle migrate仅会执行新创建的迁移。如果没有新的迁移脚本,这个命令不会执行任何操作。可以使用选项–reset来重新执行全部迁移脚本。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ truffle migrate --reset</pre>

3. 初始化迁移合约

在本节开头我们提到过一个特殊的Migrations.sol合约,那么现在就来详细了解下这个特殊合约。为了使用迁移功能,Truffle要求你要有一个迁移合约。这个合约必须包含一个特定的接口,对于大多数项目来说,这个合约只会在第一次做迁移的时候被部署,以后都不会做任何的更改了。当你使用 truffle init 来创建一个项目的时候,它会默认创建这个合约。

文件名:contracts/Migration.sol

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">pragmasolidity^0.4.4;

contractMigrations{
 addresspublicowner;
 uintpubliclast_completed_migration;

 modifierrestricted() {
   if(msg.sender==owner) _;
}

 functionMigrations() {
   owner=msg.sender;
}

 functionsetCompleted(uintcompleted) restricted{
   last_completed_migration=completed;
}

 functionupgrade(addressnew_address) restricted{
   Migrationsupgraded=Migrations(new_address);
   upgraded.setCompleted(last_completed_migration);
}
}</pre>

为了利用迁移的特性,你必须首先要部署Migration.sol合约。为此,创建以下迁移脚本:

文件名:migrations/1_initial_migrations.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varMigrations=artifacts.require("./Migrations.sol");

module.exports=function(deployer) {
 // Deploy the Migrations contract as our only task
 deployer.deploy(Migrations);
};</pre>

要部署其他合约,你可以递增数字编号前缀来创建新的迁移脚本。

4. 部署器(deployer)

你的迁移脚本会使用这deployer对象来组织部署任务。deployer对象会同步执行部署任务,因此你可以按顺序编写部署任务。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">// 先部署A,再部署B
deployer.deploy(A);
deployer.deploy(B);</pre>

另外,deployer上的每一个函数都会返回一个promise,通过promise可以把有执行顺序依赖关系的部署任务组成队列。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">// 部署A, 然后部署 B, 把A 部署后的地址传给B
deployer.deploy(A).then( function () {
return deployer.deploy(B, A.address);
});</pre>

5. deployer API

deployer对象包含许多方法,可以用来简化你的迁移工作。

(1) deployer.deploy(CONTRACT, ARGS…, OPTIONS)

这个API是用来部署合约的,contract参数传入需要部署的合约名字,args参数传入合约的构造函数需要的参数,options是一个可选参数它的值是{overwrite: true/false}, 如果 overwrite 被设置成 false, 那么当这个合约之前已经部署过了,这个deployer就不会再部署这个合约,这在当一个合约的依赖是由一个外部合约地址提供的情况下是有用的。

为了快速进行部署多个合约,你可以向deployer.deploy(…..)函数中传入一个或多个数组。

例子:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">// 部署单个合约,不带任何构造参数
deployer.deploy(A);
// 部署单个合约带有构造参数
deployer.deploy(A, arg1, arg2, ...);
// 部署多个合约,一些带构造参数,一些不带构造参数.
// 比写3次 `deployer.deploy()` 语句更快, 因为deployer可以把所有的合约部署都一次性打包提交
deployer.deploy([
[A, arg1, arg2, ...],
B,
[C, arg1]
]);
// 外部依赖的例子:
//
// overwrite: false 表示,如果 SomeDependency 合约之前已经被部署过,那么不在重新部署,直接使用之前已部署好的地址
// 如果我们的合约要运行在自己的测试链上,或者将要运行的链上没有SomeDependency合约,
// 那么把overwrite: false改成overwrite: true,表示不在检查之前SomeDependency有没有部署过,一律覆盖部署。
deployer.deploy(SomeDependency, {overwrite:  false});</pre>

(2) deployer.link(LIBRARY, DESTINATIONS)

把一个已部署好的库链接到一个或多个合约里. destinations 可以传入一个合约,也可以传入一组合约. 如果 destinations中的某个合约不依赖这个库, 那deployer 的link函数就会忽略这个合约。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">// 部署库LibA,然后把LibA 链接到合约B,然后部署合约B.
deployer.deploy(LibA);
deployer.link(LibA, B);
deployer.deploy(B);

//库LibA链接到多个合约
deployer.link(LibA, [B, C, D]);</pre>

(3) deployer.then(function() {…})

在迁移过程中使用它调用特定合约的函数来部署新的合约,为已部署的合约做一些初始化工作等。

例子:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">vara, b;
deployer.then( function() {
   // 部署合约A的一个新版本到网络上
returnA.new();
}).then( function(instance) {
a=instance;
   // 获取已部署的合约B的实例
 returnB.deployed();
}).then( function(instance) {
b=instance;
   // 使用合约B的setA()方法设置A的地址的新实例.
returnb.setA(a.address);
});</pre>

(4) 网络相关

在执行迁移时,迁移脚本会把truffle.js里配置的networks传递给你,你可以在module.exports导出函数中第二个参数位置接受这个值。

文件:truffle.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">module.exports = {
networks: {
  development: {
    host: "localhost",
    port: 8545,
    network_id: "*" // Match any network id
  }
}
};</pre>

例子:

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">module.exports=function(deployer, network) {
 if(network=="live") {
  // 当不在"live"的网络上的时候,做一些特定的操作.
} else{
  // 当在的时候,做一些其他的操作.
}
}</pre>

(5) 可用的账户

在执行迁移时,迁移脚本会把当前以太坊客户端或web3.provider中可用的账户列表传递给你,这个列表与web3.eth.getAccounts()返回的账户列表完全一样。你可以在module.exports导出函数中第三个参数位置接受这个值。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">module.exports=function(deployer, network, accounts) {
 //在你的迁移脚本中使用账户
}</pre>

7

合约交互

以太坊中将向以太坊网络写入数据和从以太坊网络中读取数据这两种操作做了区分。一般来说,写数据被称为交易(transaction),而读取数据称为调用(call)。交易和调用的处理方式非常不同,并且具有以下特征。

1、交易(transaction)

交易会从根本上改变了网络的状态。简单的交易有:发送以太币到另一个账户。复杂的交易有:调用一个合约的函数,向网络中部署一个合约。交易的显著特征是:

交易可以写入或修改数据;

交易花费以太币运行,就是我们所说的gas;

交易需要时间处理。

当你通过交易调用合约的函数时,我们将无法立即获得智能合约的返回值,因为该交易当前只是被发送,离被打包、执行还有一段时间。通常,通过交易执行的函数将不会立刻返回值,它们将返回一个交易ID。所以总结一下,一个交易一般有如下特征:

消耗gas(以太币)

更改网络的状态

不会立即处理

不会立刻返回一个返回值(只有一个交易ID)

2、 调用(CALL)

另一方面,调用则完全不一样。调用可以在网络上执行代码,但不会永久更改数据。调用可以免费运行,不需要花费gas。调用的显著特征是:调用是用来读取数据。当你通过调用执行合约函数时,你将立即收到返回值。总而言之,调用是:

是免费的(不消耗gas)

不会更改网络的状态

会被立即处理

会立刻返回一个值

决定使用交易还是调用,依据很简单:要读取数据还是写入数据。

3、 合约抽象

合约抽象是Javascript和以太坊合约交互的中间层粘合剂。简而言之,合约抽象帮我们封装好了代码,它可以让你和合约之间的交互变得简单,从而让你不必关心合约调用细节。Truffle通过truffle-contract模块来使用自己的合约抽象。合约抽象中的函数和我们合约中的函数是一样的。

为了使用合约抽象和合约交互,我们需要通过npm安装truffle-contract模块

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">$ cd myproject
$ npm init -y
$ npm install --save truffle-contract@3.0.1
$ npm install --save web3@0.20.0</pre>

4、 与合约交互

(1)Call 方式交互

介绍完上述概念后,现在我们可以和之前部署好的Storage.sol合约交互了,首先我们以call方式调用合约。

文件:call.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varWeb3=require("web3");

varcontract=require("truffle-contract");
vardata=require("../build/contracts/Storage.json");

// 返回合约抽象
varStorage=contract(data);

varprovider=newWeb3.providers.HttpProvider("http://localhost:8545");
Storage.setProvider(provider);

// 通过合约抽象与合约交互
Storage.deployed().then(function(instance) {
   returninstance.get.call(); // call 方式调用合约
}).then(result=>{
   console.info(result.toString());// return 0
}).catch(err=>{
   // 报错了!在这里处理异常信息
});</pre>

注意:

我们必须明确地调用.call()函数,告诉Ethereum网络知道我们不会修改区块链上的数据。

当调用成功是,我们会收到一个返回值,而不是交易ID。

(2)Transaction 方式交互

接下来我们以transaction方式给Storage.sol合约中storedData变量赋值为42,

文件:transaction.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varWeb3=require("web3");

varcontract=require("truffle-contract");
vardata=require("../build/contracts/Storage.json");

// 返回合约抽象
varStorage=contract(data);

varprovider=newWeb3.providers.HttpProvider("http://localhost:8545");
Storage.setProvider(provider);

varstorageInstance;
Storage.deployed().then(function(instance) {
   storageInstance=instance;

   //以transaction方式与合约交互
   returnstorageInstance.set(42,{from:Storage.web3.eth.accounts[0]});
}).then(result=>{
// result 是一个对象,它包含下面这些值:
   //
   // result.tx     => 交易hash,字符型
   // result.logs   => 在交易调用中触发的事件,数组类型
   // result.receipt => 交易的接收对象,里面包含已使用的gas 数量

   console.info(result.tx);//返回交易ID
}).then(()=>{
   // 调用Storage get 方法
   returnstorageInstance.get.call();
}).then(result=>{
   console.info(result.toString());// 返回 42 ,说明我们之前的调用成功了!
}).catch(err=>{
   // 报错了!在这里处理异常信息
});</pre>

上面的代码有一些需要说明的地方:

我们直接调用这合约抽象的 set 方法。 默认情况下,这个操作会向区块链网络中发送一笔交易。也可以显式调用storageInstance.set.sendTransaction(42,{from:Storage.web3.eth.accounts[0]}),表明是以transaction方式交互

当这个交易成功发出后,回调函数只有在交易被成功打包处理后才会激活,这省去了你自己写判断语句检查交易状态的麻烦。

我们传递了一个对象给set函数的第二个参数。注意:在我们的Storage.sol合约代码中set函数并没有第三个参数,这第三个参数是合约抽象API里的。在合约抽象的所有函数中,你都可以向它们传入一个对象作为最后一个参数,在这个对象中你可以写入一些有关交易细节,在这个例子中,我们在对象中写入from字段,以确保这个交易是来自 web3.eth.accounts[0]。

5、 添加一个新合约到网络

在上面的所有例子中,我们使用的是一个已部署好的合约抽象,我们可以使用合约抽象的.new()函数来部署自己的合约。

文件:new.js

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varWeb3=require("web3");

varcontract=require("truffle-contract");
vardata=require("../build/contracts/Storage.json");

// 返回合约抽象
varStorage=contract(data);

varprovider=newWeb3.providers.HttpProvider("http://localhost:8545");
Storage.setProvider(provider);

varstorageInstance;

// new 部署新的合约
Storage.new({from:Storage.web3.eth.accounts[0],gas:1000000}).then(function(instance) {
   storageInstance=instance;
   // 输出新合约的地址
   console.log(instance.address); // 0xfc628dd79137395f3c9744e33b1c5de554d94882
}).catch((err) =>{
   console.info(err)
   // 报错了!在这里处理异常信息
});</pre>

6、 使用现有合约地址

如果你已经有一个合约地址,你可以通过这个地址创建一个新的合约抽象。

<pre style="margin: 0px 0px 10px; padding: 9.5px; border-radius: 4px; background: rgb(245, 245, 245); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; max-width: 100%; color: rgb(51, 51, 51); letter-spacing: 0.544px; text-align: justify; overflow: auto; font-family: Menlo, Monaco, Consolas, monospace; font-size: 13px; line-height: 1.42857; word-break: break-all; border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204); box-sizing: border-box !important; word-wrap: break-word !important;">varWeb3=require("web3");

varcontract=require("truffle-contract");
vardata=require("../build/contracts/Storage.json");

// 返回合约抽象
varStorage=contract(data);

varprovider=newWeb3.providers.HttpProvider("http://localhost:8545");
Storage.se                    </pre>

内容来源:区块链兄弟

原文来源:《区块链开发实战-以太坊关键技术与案例分析》-机械工业出版社

作者:吴寿鹤

《区块链100讲》专栏策划及内容编辑:HiBlock区块链社区Cynthia

如需转载,需申请并注明专栏及原文出处。

以下是我们的社区介绍,欢迎各种合作、交流、学习:)

image

【区块链开发入门】(四) Truffle详解篇1 目录一、什么是Truffle二、安装Truffle 一、什么是Truffle Truffle是针对基于以太坊的Solidity语言的一套开发框架。本身基于Javascript。Truffle是一个世界级的开发环境,测试框架,以太坊的资源管理通道,旨在让以太坊上的开发变得简单,Truffle有以下: 内置的智能合约编译,链接,部署和二进制文件的管理。 利用快速开发的自动合约测试。 可脚本化的,可扩展的部署与发布框架。 网络管理,用于部署到任意数量的公网或私网的网络环 支持持续集成可配置构建管道。 与合约直接 阅读详情

相关推荐

Dapp开发利器--Truffle三剑客之Ganache

一、Truffle Suite        Truffle Suite 为以太坊上应用程序(Dapp)的快速开发提供工具服务,它主要有以下三个产品:truffle、ganache和drizzle。这三个工具对快速开发以太坊DAPP有很大的帮助,所以我暂且把它三个产品叫着“Truffle三剑客”。   &n...

天草降临的博客 1万+

区块链之以太坊智能合约与DApp

以太坊是一个平台,它上面提供各种模块让用户来搭建应用,如果将搭建应用比作造房子,那么以太坊就提供了墙面、屋顶、地板等模块,用户只需像搭积木一样把房子搭起来,因此在以太坊上建立应用的成本和速度都大大改善。具体来说,以太坊通过一套图灵完备的脚本语言(Ethereum Virtual Machinecode,简称EVM语言)来建立应用,它类似于汇编语言。我们知道,直接用汇编语言编程是非常痛苦的,但以太坊里的编程并不需要直接使用EVM语言,而是类似C语言、python、Lisp等高级语言,再通过编译器转成Evm语言。上面所说的平台之上的应用,其实就是合约,这是以太坊的核心。合约是一个活在以太坊系统里的自动代理人,他有一个自己的以太币地址,当用户向合约的地址里发送一笔交易后,该合约就被激活,然后根据交易中的额外信息,合约会运行自身的代码,最后返回一个结果,这个结果可能是从合约的地址发出另外一笔交易。需要指出的是,以太坊中的交易,不单只是发送以太币而已,它还可以嵌入相当多的额外信息。如果一笔交易是发送给合约的,那么这些信息就非常重要,因为合约将根据这些信息来完成自身的业务逻辑。合约所能提供的业务,几乎是无穷无尽的,它的边界就是你的想象力,因为图灵完备的语言提供了完整的自由度,让用户搭建各种应用。白皮书举了几个例子,如储蓄账户、用户自定义的子货币等。 2013年年末,以太坊创始人Vitalik Buterin发布了以太坊初版白皮书,启动了项目。2014年7月24日起,以太坊进行了为期42天的以太币预售。2016年初,以太坊的技术得到市场认可,价格开始暴涨,吸引了大量开发者以外的人进入以太坊的世界。中国三大比特币交易所之二的火币网及OKCoin币行都于2017年5月31日正式上线以太坊。 [1] 自从进入2016年以来,那些密切关注数字货币产业的人都急切地观察着第二代加密货币平台以太坊的发展动向。作为一种比较新的利用比特币技术的开发项目,以太坊致力于实施全球去中心化且无所有权的的数字技术计算机来执行点对点合约。简单来说就是,以太坊是一个你无法关闭的世界计算机。加密架构与图灵完整性的创新型结合可以促进大量的新产业的出现。反过来,传统行业的创新压力越来越大,甚至面临淘汰的风险。比特币网络事实上是一套分布式的数据库,而以太坊则更进一步,她可以看作是一台分布式的计算机:区块链是计算机的ROM,合约是程序,而以太坊的矿工们则负责计算,担任CPU的角色。这台计算机不是、也不可能是免费使用的,不然任何人都可以往里面存储各种垃圾信息和执行各种鸡毛蒜皮的计算,使用它至少需要支付计算费和存储费,当然还有其它一些费用。最为知名的是2017年初以摩根大通、芝加哥交易所集团、纽约梅隆银行、汤森路透、微软、英特尔、埃森哲等20多家全球top金融机构和科技公司成立的企业以太坊联盟。而以太坊催生的加密货币以太币近期又成了继比特币之后受追捧的资产。  智能合约的潜在应用很多。彭博社商业周刊称它是“所有人共享但无法篡改的软件”。更高级的软件有可能用以太坊创建网络商店。  以太坊是一个平台,它上面提供各种模块让用户来搭建应用,如果将搭建应用比作造房子,那么以太坊就提供了墙面、屋顶、地板等模块,用户只需像搭积木一样把房子搭起来,因此在以太坊上建立应用的成本和速度都大大改善。具体来说,以太坊通过一套图灵完备的脚本语言(Ethereum Virtual Machinecode,简称EVM语言)来建立应用,它类似于汇编语言。我们知道,直接用汇编语言编程是非常痛苦的,但以太坊里的编程并不需要直接使用EVM语言,而是类似C语言、python、Lisp等高级语言,再通过编译器转成Evm语言。上面所说的平台之上的应用,其实就是合约,这是以太坊的核心。合约是一个活在以太坊系统里的自动代理人,他有一个自己的以太币地址,当用户向合约的地址里发送一笔交易后,该合约就被激活,然后根据交易中的额外信息,合约会运行自身的代码,最后返回一个结果,这个结果可能是从合约的地址发出另外一笔交易。需要指出的是,以太坊中的交易,不单只是发送以太币而已,它还可以嵌入相当多的额外信息。如果一笔交易是发送给合约的,那么这些信息就非常重要,因为合约将根据这些信息来完成自身的业务逻辑。合约所能提供的业务,几乎是无穷无尽的,它的边界就是你的想象力,因为图灵完备的语言提供了完整的自由度,让用户搭建各种应用。白皮书举了几个例子,如储蓄账户、用户自定义的子货币等。 2013年年末,以太坊创始人Vitalik Buterin发布了以太坊初版白皮书,启动了项目。2014年7月24日起,以太坊进行了为期42天的以太币预售。2016年初,以太坊的技术得到市场认可,价格开始暴涨,吸引了大量开发者以外的人进入以太坊的世界。中国三大比特币交易所之二的火币网及OKCoin币行都于2017年5月31日正式上线以太坊。 [1] 

开发一个简单的智能合约

开发简单的智能合约,从环境搭建,开发步骤,源代码,各方面解析,成功开发并运行一个智能合约

weixin_51194902的博客 4670

truffle入门(一)--【区块链】

下载安装nodejs,快速入门truffle进行测试

m0_72435337的博客 1362

Ganache+Truffle+MateMask实现第一个Dapp(Windows)

Ganache+Truffle+MateMask实现第一个Dapp

qq_42042158的博客 4466

Truffle框架和Ganache本地私链

Truffle框架和Ganache本地私链 安装Truffle Truffle是一个世界级的开发环境,测试框架,以太坊的资源管理通道,致力于让以太坊上的开发变得简单。 Github源码地址 https://github.com/trufflesuite/truffle 安装Npm和NodeJS 安装Truffle npm install -g truffle ...

MyHerux的博客 4876

Truffle + Ganache:以太坊智能合约开发与部署实战

本文通过一个简单的示例,演示了如何使用 Truffle 和 Ganache 开发、部署以太坊智能合约的全过程。从环境搭建、合约编写、部署到测试,每一步都进行了详细的说明。掌握这些基础知识,将为你进一步开发复杂的去中心化应用(DApp)打下坚实的基础。

CiaoAI做市机器人,让您的代币更具流动性和活跃性 884

一篇文档教会你使用truffle合约测试(迁移脚本和测试脚本)

上篇文档写了如何使用truffle的基本命令,这篇文档来教大家如何写迁移脚本和测试脚本。

m0_74471174的博客 2039

区块链DAPP-基于Truffle框架的宠物商店

1.业务背景 Pete有一个宠物店(Pete's Pet Shop),该商店在给定时间可以容纳16只宠物,并且已经有了宠物数据。他希望基于Truffle框架开发一个完全去中心化应用,让大家来领养宠物。 2.环境准备 安装Node:下载地址https://nodejs.org/en/download/ 安装Truffle :npm install -g truffle 安装ganache-cli:npm install -g ganache-cli 注意:Node、Truffle、ganach.

ytsm04的专栏 3710

区块链开发入门:从零基础到创建第一个智能合约

区块链和智能合约的基础概念。如何配置开发环境并安装所需工具。如何使用Solidity编写一个简单的智能合约。如何使用Truffle框架编译、部署并与智能合约交互。接下来,你可以继续深入学习智能合约的高级特性,探索更多区块链平台,或者开发自己的去中心化应用(DApp)。智能合约的应用范围非常广泛,从金融到游戏,几乎所有涉及到合约执行的场景都可以借助智能合约实现去中心化和自动化的管理。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3282

ROS应用之如何配置RTOS满足机器人系统中的实时要求

实时操作系统(RTOS)基本概念实时操作系统(RTOS)是设计用于实时应用的操作系统,其主要目标是在确定的时间内完成任务。RTOS的任务调度算法和优先级控制机制能够确保高优先级任务按时完成。精确的传感器数据采集:传感器数据需要在规定时间内采集并传输给控制系统。快速响应外部事件:对于控制系统,需要确保指令在最短的时间内得到响应。任务的调度周期:任务的周期可以通过公式计算,其中 ftask 是任务的调度频率。优先级分配。

weixin_68094467的博客 1008

Python 区块链开发实战:从零到一构建智能合约

通过上述步骤,我们使用 Python 构建了一个简单的 ERC-20 智能合约,并实现了与其交互的功能。在实际应用中,智能合约可以用于构建去中心化应用(DApp),实现自动化的业务逻辑。Python 作为一种高效的开发语言,能够帮助开发者快速实现区块链应用。在未来,随着区块链技术的不断发展,Python 在区块链领域的应用将更加广泛。开发者可以利用 Python 的优势,构建更为复杂和高效的区块链应用。

CiaoAI做市机器人,让您的代币更具流动性和活跃性 1955

西门子 标准程序解读---> 机器手抓取和涂胶控制程序

摘要 该程序实现机械手在OP70/OP90工位的自动化控制,核心功能包括: 流程控制:分段(Seg1-Seg11)管理抓件、涂胶、放件等动作,结合DB1050/DB1250数据块监控工位状态及变位机位置反馈。 安全机制:配置干涉区(FC124)、实时检测安全光/急停信号,防止碰撞;服务程序(FB191)支持维修位触发与安全隔离。 参数配置:通过DB块关联机器人速度、节拍(FB27)、车型编码(如空过=2)及手自动模式(DB70.DBX21.2)。 应用场景:适用于汽车焊接/装配线

工控智联驿站 1239

Truffle智能合约开发全流程实践

通过搭建Truffle环境,完成智能合约的编写、编译、部署与测试,并结合前端界面实现DApp交互。使用Ganache模拟区块链网络,Web3.js连接MetaMask,完整展示从合约到应用的开发流程。

weixin_36474966的博客 640

AURIX™ TC49x芯片手册中文分享(二)

主要内容为第一章、功能模块的特征

xibaofenqi的博客 1563

微信开放标签wx-open-launch-app样式失效?手把手教你正确设置点击区域(附完整代码)

本文详细解析了微信开放标签`wx-open-launch-app`样式失效和点击无响应的常见问题,提供了完整的解决方案和代码示例。通过分析标签内部实现机制,指导开发者正确设置点击区域和样式,确保跨平台兼容性和用户体验优化。

joy55的博客 320

Truffle-Petshop

Truffle-Petshop搭建指南

Samblue_M的博客 2611

CANoe.Diva实战:基于CDD的UDS诊断自动化测试全流程解析

本文详细解析了使用CANoe.Diva进行基于CDD的UDS诊断自动化测试的全流程,包括环境搭建、CDD文件配置、测试范围设置、用例生成与验证、CANoe集成测试及报告分析。通过实战经验分享,帮助工程师快速掌握诊断自动化测试技巧,提升测试效率与质量。

weixin_29258297的博客 219

(四)以太坊——运用truffle框架部署第一个DAPP ---- Pet-Shop

内容大纲: 本项目是在以太坊上开的一个宠物领养的DAPP,借助了truffle框架和ganache进行合约部署。同时实现web端与区块链的交互。 1.设置开发环境 2.使用 Truffle Box 创建一个 Truffle 项目 3.编写智能合约 4.编译和部署智能合约 5.测试智能合约 6.创建用户界面以与智能合约交互 7.在浏览器中与 dapp 交互 开发环境: Node.js v8+ LTS 和 npm(Node 自带) git ganache go开发环境 chrome上的metamask钱

qq_42102911的博客 2671

2025 年第十五届 APMCM 亚太地区大学生数学建模竞赛A题 农业灌溉系统优化

该摘要探讨了农业灌溉系统优化面临的复杂挑战,涉及智能灌溉技术的应用与资源配置问题。研究聚焦于一个1公顷的方形农场案例,该农场种植三种作物并面临动态环境条件(土壤类型、气象变化)。系统优化需平衡河流引水(非线性成本函数:C=50L^1.2+0.1Q^1.5)与储水罐灌溉(成本5元/升容积)两种方案,同时满足喷灌技术约束(喷头间距≥15米,覆盖半径15米)。关键矛盾体现在"平河旱储"的水资源调配策略与多作物需水量差异之间的协调,需通过传感器数据实时调整灌溉方案以实现效率最大化。(149字)

m0_60472361的博客 642

(计算机组成原理)第二章数据的表示和运算-第二节:数字电路基础知识

本文介绍了计算机组成原理中的逻辑门电路、多路选择器和三态门。逻辑门电路包括基本逻辑运算(与、或、非)和复合逻辑运算(与非、或非、异或、同或),这些运算通过门电路实现,并满足分配律和结合律。多路选择器(MUX)用于从多个输入信号中选择一个输出,广泛应用于数据选择、资源共享和逻辑函数实现等场景。三态门则具有三种输出状态(高电平、低电平、高阻态),常用于总线控制和信号隔离。这些元件在数字电路设计和计算机系统中具有重要作用。

快乐江湖的博客 2475

Truffle在ganache-cli部署合约

准备 确保安装好了 Truffle Framework 和 Ganache CLI. $ sudo npm install -g truffle $ sudo npm install -g ganache-cli 开始 // SPDX-License-Identifier: MIT pragma solidity > 0.4.21; contract Storage { mapping (string => string) private _store; funct

yzpbright的博客 8071

NEU-DET 冷轧钢缺陷检测:基于 YOLOv8 的目标检测与可视化 UI 实现

冷轧钢的生产过程中,由于设备故障、工艺问题或者人为因素,钢板表面可能会出现多种缺陷,如划痕、裂纹、孔洞等,这些缺陷会严重影响钢材的质量。它比之前的版本(如 YOLOv5、YOLOv4)在速度和精度上都有显著提升,并且对硬件要求较低,适合进行工业界面和嵌入式系统的应用。这些版本相较于更大型的模型(如 YOLOv8x)具有更快的推理速度和较低的资源占用,适合工业生产线中的实时应用。通过将训练好的模型部署到工业生产线摄像头中,我们可以实现实时的缺陷检测,极大地提升生产效率和产品质量。

YOLO 739

区块链开发工具大全:Blockchain for Software Engineers推荐的Truffle、Ganache和IPFS终极指南 [特殊字符]

在当今快速发展的区块链技术领域,掌握正确的开发工具是成功的关键。Blockchain for Software Engineers项目为软件工程师们精心整理了一套完整的区块链开发工具资源,特别是以太坊生态中的三大核心工具:Truffle、Ganache和IPFS。这些工具能够帮助开发者从零开始构建去中心化应用(DApp),大大提升开发效率和代码质量。 ## 📊 为什么需要专业的区块链开发工具?

gitblog_00457的博客 1007

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

利用Truffle实现一个区块链捐款系统

选题背景 慈善捐款越来越普遍,但该行业仍然存在着多年运作累积的很多问题。最令人诟病的就是善款去向不明、信息不公开,而且公益项目,每一笔善款都代表着公众对需要帮助的人的爱心和善意,一旦曝出贪污等不法行为,打击几乎是毁灭性的。在某些特定的情况下,这些问题也阻碍了人们奉献爱心。而区块链的出现正好为慈善捐款的公平公正提供了基础。 依据 区块链技术具有数据不可篡改和可追溯性,可以用来构建监管部门所需要的,...

miracle33的博客 3174

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

上一篇: 众说区块链:区块链在食品安全溯源领域中的应用
下一篇: 如何搭建以太坊测试链(附教程)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值