以前公司有个业务线专门搞区块链,虽然大家都很熟,随时沟通,但是由于当时专注与Data & AI所以对区块链本身仅仅停留在理论和概念的层面,直至离开也没有机会加入搞一个实际的区块链项目去体验体验。

但是说回来,我自己对区块链的感觉一直是觉得缺少实际的业务场景,现在大家提到区块链似乎第一想到的就是:币。就像目前一提到元宇宙最容易让人有感官认识的就是:游戏。

无论区块链的实践者如何解释场景,最终都会导向币,就像目前无论元宇宙如何强调虚拟世界,最后出来的东西还是游戏或者泛娱乐,何其相似。

我之前提过元宇宙的一些概念:https://baifachuan.com/posts/4b3975cc.html 一个真正的元宇宙产品应该具备八大要素,分别是:身份、朋友、沉浸感、低延迟、多元化、随地、经济系统、文明。

但是这里有个问题就是如果是虚拟世界,那么数据怎么存,交易怎么进行?显然好像区块链的思想更符合,做一个分布式的账本系统用来记录元宇宙的数据,于是似乎元宇宙+区块链这两东西结合在一起又大有可为了,这难道就是负负得正。

说回来区块链下的智能合约,首先需要理解一下什么是智能合约:

1
2
智能合约(Smart contract )是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于1995年由Nick Szabo首次提出。
智能合约的目的是提供优于传统合约的安全方法,并减少与合约相关的其他交易成本。

也就是相比目前已经存在的集中交易机制下驱动的合约来说,区块链下的智能合约有如下优点:

  • 不需要中间人
  • 费用低
  • 代码就是规则
  • 区块链网络中有多个备份,不用担心丢失
  • 避免人工错误
  • 无需信任,就可履行协议
  • 匿名履行协议

如果想开发一个智能合约的dem,目前使用以太坊Ethereum作为底层设施是一种使用比较多的方案,以太坊(Ethereum)虚拟机是执行智能合约代码的引擎。也就是Solidity语言,开发智能合约程序,编译成以太坊(Ethereum)虚拟机支持的字节码/bytecode,然后该程序就可以在虚拟机中执行。

环境搭建

开发智能合约需要依赖以下模块:

  • Node 与 NPM
  • Truffle 框架
  • Ganache
  • Metamask
  • VScode 与 Solidity插件

通过npm install -g truffle安装truffle,Truffle是以太坊开发框架,内置了智能合约编译、链接、部署等功能,安装完后通过truffle --version检查是否安装成功。

Ganache则需要在 http://trufflesuite.com/ganache/ 这里下载,上面的模块之间大概的关系就是:node不说了,基本编程环境,Truffle负责把写的合约翻译成虚拟机支持的字节码,Ganache可以在本地创建区块链网络来测试我们的程序,也就是提供了一个本地的区块链网络环境,它会创建一个本地区块链网络,给我们分配10个外部账号,每个帐户都有100个假的以太币。
主页面是这个样子:
image

Metamask是一个Chrome插件形式的以太坊节点/钱包,使用Metamask连接到本地区块链网络或实际的以太坊网络,并与我们的智能合约交,把这些环境都准备好,开发智能合约的环境也就差不多了。

开发合约

首先创建项目目录:

1
2
mkdir mydapp
$ cd mydapp

然后使用truffle init初始化项目,将生成项目模板文件:

1
$ truffle init

可以查看一下生成的项目目录:

1
2
3
4
5
6
7
8
└> tree -L 3
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js
  • contracts 目录 智能合约源文件目录,现在已经有了一个Migrations.sol源文件,功能是迁移/部署/升级智能合约。
  • migrations 目录 迁移文件目录,迁移文件都是javascript脚本,帮助我们把智能合约部署到以太坊。
  • test 目录 测试代码目录。
  • truffle-config.js 文件 Truffle项目配置文件,例如可以在里面配置网络。

创建package.json文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name": "ethereum-demo",
"version": "1.0.0",
"description": "以太坊demo",
"main": "truffle-config.js",
"directories": {
"test": "test"
},
"scripts": {
"dev": "lite-server",
"test": "echo \"Error: no test specified\" && sexit 1"
},
"author": "fcbai@fcbai.com",
"license": "ISC",
"devDependencies": {
"@truffle/contract": "^4.0.33",
"dotenv": "^8.1.0",
"lite-server": "^2.5.4",
"truffle-hdwallet-provider": "^1.0.17"
}
}

创建智能合约文件MyContract.sol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 声明solidity版本
pragma solidity ^0.5.0;

// 声明智能合约MyContract,合约的所有代码都包含在花括号中。
contract MyContract {

// 声明一个名为value的状态变量
string value;

// 合约构造函数,每当将合约部署到网络时都会调用它。
// 此函数具有public函数修饰符,以确保它对公共接口可用。
// 在这个函数中,我们将公共变量value的值设置为“myValue”。
constructor() public {
value = "myValue";
}

// 本函数读取值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
// 它还包含view修饰符并指定一个字符串返回值。
function get() public view returns(string memory ) {
return value;
}

// 本函数设置值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
function set(string memory _value) public {
value = _value;
}
}

执行truffle compile编译项目后可以看到多了一个build目录,该目录下生成了新文件:./build/contract/MyContract.json ,这个文件是智能合约编译后的文件。

部署合约

修改项目根目录下的truffle-config.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
}
},
solc: {
optimizer: {
enabled: true,
runs: 200
}
}
}

这些网络配置,包括ip地址、端口等,也就是Ganache的网络配置。然后在migrations目录中创建迁移脚本,告诉Truffle如何部署智能合约,在该目录中创建文件2_deploy_contracts.js:

1
2
3
4
5
var MyContract = artifacts.require("./MyContract.sol");

module.exports = function(deployer) {
deployer.deploy(MyContract);
};

执行truffle migrate将智能合约部署到本地的Ganache区块链网络。

使用 truffle console 访问智能合约

truffle console 是区块链开发人员的强大工具,这是一个命令行工具,可以在命令行中执行javascript代码,与智能合约进行交互:

1
$ truffle console

执行:

1
2
3
4
5
6
MyContract.deployed().then((instance) => { app = instance } )
app.get()
// => 'myValue'
app.set('New Value')
app.get()
// => 'New Value'

可以成功触发合约。

智能合约测试(truffle test)

命令行去测试显然不是最好的方式,在项目根目录下的test目录中,添加测试脚本文件: MyContract.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 首先,`require`合约并将其分配给一个变量`MyContract`
const MyContract = artifacts.require('./MyContract.sol');

// 调用“contract”函数,并在回调函数中编写所有测试
// 回调函数提供一个“accounts”变量,表示本地区块链上的所有帐户。
contract('MyContract', (accounts) => {

// 第1个测试:调用get()函数,检查返回值,测试合约中value初始值是否是: 'myValue'
it('initializes with the correct value', async () => {
// 获取合约实例
const myContract = await MyContract.deployed()
const value = await myContract.get()
// 使用断言测试value的值
assert.equal(value, 'myValue')
})

// 第2个测试: 调用set()函数来设置value值,然后调用get()函数来确保更新了值
it('can update the value', async () => {
const myContract = await MyContract.deployed()
myContract.set('New Value');
const value = await myContract.get()
assert.equal(value, 'New Value')
})
})

运行:

1
$ truffle test

可以完成整个测试,可以看到以太坊提供了一个合约的运行环境,但是执行合约是需要消费币的,所以本质上区块链如何去使用,真的还得看实际的场景。


扫码手机观看或分享: