智能合约
以太坊是一个运行着智能合约的分布式平台,智能合约本质就是脚本,这些脚本可以处理各种业务逻辑来利用以太坊区块链的能力,比如彩票、拍卖、物流跟踪等等。这也正是以太坊区别于比特币的最重要的属性,定位来说以太坊旨在成为一个平台,而比特币则是一个货币体系。智能合约赋能给以太坊无限想象力和更强大的生命力。
一个简单的例子,就是A转账给B,在比特币和以太坊中大概都怎么实现的:
以太坊智能合约实现的方式貌似能看懂,比较易读。事实也是这样的,智能合约使得区块链的扩展性更强,且实现上更简洁,从而让以太坊发展成为目前最大的一个区块链开发平台。
随着智能合约的发展,智能合约构建的组织如同现实商业社会一样的运行,这样形成的去中心化组织网络会变得极其复杂和自治,会出现各种形态:DAPP(去中心化应用)DAO(去中心化自治组织)DAC(去中心化自治公司)DAS(去中心化自治社会).
DAPP
DAPP是去中心化的APP,DAPP和普通的App原理一样,除了他们是完全去中心化的,在以太坊网络本身自己的节点来运作的DAPP,不依赖于任何中心化的服务器,DAPP是去中心化的,可以完全自动地运行。
以太坊中一般会认为智能合约就是DAPP,当然更准确的可以认为智能合约相当于服务器后台,另外要实现用户体验,还需要UI交互界面,通过RPC与后台对接,那么DAPP就是包含完整的智能合约+用户UI交互界面。
智能合约开发
搭建开发环境
智能合约的开发环境需要:
· Truffle:是以太坊的开发环境、测试框架和资产通道。换句话说,它可以帮助你开发、发布和测试智能合约等等。
· Ganache:以前叫作 TestRPC,如果你读过几个月前的教程的话,有可能他们在使用TestRPC 的情境下配合使用了 Truffle,它在 TestRPC 和Truffle 的集成后被重新命名为 Ganache。Ganache 的工作很简单:创建一个虚拟的以太坊区块链,并生成一些我们将在开发过程中用到的虚拟账号。
· Mist:Mist 是一个分布式网络 apps 的浏览器,相当于是只针对 Dapps 的 Chrome 或Firefox。目前来说,它仍然是不安全的,所以你还不能在不受信任的 Dapp 中使用它。
· 以太坊钱包:它是 Mist 的一个版本,但只启动一个 Dapp ——以太坊钱包。Mist 和以太坊钱包只是 UI(用户界面)前端,我们还需要一个将我们连接到以太坊区块链的核心程序(它可以是一个真正的以太坊区块链,也可以是一个测试版的)。
· Geth:Geth 是把你连接到区块链的核心应用程序,它也可以启动一个新的区块链(在我们这个示例中,我们将创建一个本地测试网区块链),创建合约,挖掘以太币等。
Truffle和Ganache都是基于NodeJS,所以首先得安装Node和NPM。本文是CentOS7环境,
Node版本如下:
$ node -v
v7.0.0
$ npm -v
3.10.8
安装Truffle:
$ npm install -g truffle |
安装成功查询:
$ truffle version Truffle v4.1.11 (core: 4.1.11) Solidity v0.4.24 (solc-js) |
安装Ganache命令行工具:
$ npm install -g ganache-cli |
创建Truffle工程
使用Truffle来创建一个工程:
$ mkdir my-dapp
$ cd my-dapp/
$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
第一步在工程contracts 目录下创建一个Solidity 脚本:
Wrestling.sol
pragma solidity ^0.4.18;
/**
* Example script for the Ethereum development walkthrough
*/
contract Wrestling {
/**
* Our wrestlers
*/
address public wrestler1;
address public wrestler2;
bool public wrestler1Played;
bool public wrestler2Played;
uint private wrestler1Deposit;
uint private wrestler2Deposit;
bool public gameFinished;
address public theWinner;
uint gains;
/**
* The logs that will be emitted in every step of the contract's life cycle
*/
event WrestlingStartsEvent(address wrestler1, address wrestler2);
event EndOfRoundEvent(uint wrestler1Deposit, uint wrestler2Deposit);
event EndOfWrestlingEvent(address winner, uint gains);
/**
* The contract constructor
*/
constructor() public {
wrestler1 = msg.sender;
}
/**
* A second wrestler can register as an opponent
*/
function registerAsAnOpponent() public {
require(wrestler2 == address(0));
wrestler2 = msg.sender;
emit WrestlingStartsEvent(wrestler1, wrestler2);
}
/**
* Every round a player can put a sum of ether, if one of the player put in twice or
* more the money (in total) than the other did, the first wins
*/
function wrestle() public payable {
require(!gameFinished && (msg.sender == wrestler1 || msg.sender == wrestler2));
if(msg.sender == wrestler1) {
require(wrestler1Played == false);
wrestler1Played = true;
wrestler1Deposit = wrestler1Deposit + msg.value;
} else {
require(wrestler2Played == false);
wrestler2Played = true;
wrestler2Deposit = wrestler2Deposit + msg.value;
}
if(wrestler1Played && wrestler2Played) {
if(wrestler1Deposit >= wrestler2Deposit * 2) {
endOfGame(wrestler1);
} else if (wrestler2Deposit >= wrestler1Deposit * 2) {
endOfGame(wrestler2);
} else {
endOfRound();
}
}
}
function endOfRound() internal {
wrestler1Played = false;
wrestler2Played = false;
emit EndOfRoundEvent(wrestler1Deposit, wrestler2Deposit);
}
function endOfGame(address winner) internal {
gameFinished = true;
theWinner = winner;
gains = wrestler1Deposit + wrestler2Deposit;
emit EndOfWrestlingEvent(winner, gains);
}
/**
* The withdraw function, following the withdraw pattern shown and explained here:
* http://solidity.readthedocs.io/en/develop/common-patterns.html#withdrawal-from-contracts
*/
function withdraw() public {
require(gameFinished && theWinner == msg.sender);
uint amount = gains;
gains = 0;
msg.sender.transfer(amount);
}
}
Wrestling实现的是一个角力的游戏,在这个游戏中,每一轮的比赛,参与者都可以投入一笔钱,如果一个人投入的钱大于等于另一个人的两倍(总计),那他就赢了。
关于代码的解读参考http://www.cocoachina.com/blockchain/20180312/22550.html
第二步在工程目录migrations创建一个部署脚本:
2_deploy_contracts.js
const Wrestling = artifacts.require("./Wrestling.sol")
module.exports = function(deployer) {
deployer.deploy(Wrestling);
};
这个部署脚本的作用是导入Wrestling.sol然后部署到区块链中。