罗韭菜的超详细dapp从零实战(二)-- 编写智能合约与truffle

使用solidity语言撰写智能合约

  • Ethereum上的智能合约需要使用solidity语言来撰写。虽然还有其他能用来撰写智能合约的语言如Serpent(类Python)、lll(类Fortran)

  • 但目前看到所有公开的智能合约都是使用solidity撰写。

  • solidity还是比较像Java或C#。因为和Javascript不同,solidity与Java或C#同属于强类型(Strong Type,在定义变数时需要指定类型)语言、在定义函式(function)时同样需指定回传的类型(type)、同样也需要先编译才能执行。这些特性都是Javascript所不具备的。

关于solidity编写智能合约的具体语法参见笔者专题

开发前的准备

  • 本文将使用当前最活跃的智能合约开发框架truffle为基础来开发。ENS(Ethereum Name Service)也是采用truffle框架。其他选择还有embark等。

  • 测试网:test rpc。 毕竟真实网络需要以太币,且操作需要等待十几秒,性价比不高。testrpc中也包含了Javascript版本的Ethereum虚拟机(Ethereum Virtual Machine),因此可以完整地执行智能合约。
    -编译器: atom,好处之前说过

环境准备

  • node.js (自行安卓)
  • 安装truffle
$ npm install -g ethereumjs-testrpc truffle
  • 启动testrpc
luoxuedeMBP:~ luoxue$ testrpc
EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)

Available Accounts
==================
(0) 0x48e9abd440ff12f0f5bd457d0205d64a2c047973
(1) 0x14692d8b82328f29016db341c15f59585531ab58
(2) 0x0ff04903afd3dc4791ea5b747804de6cd6c4c513
(3) 0x4d77b3d7cadee90f4c90af72be75bd2ac88a72b5
(4) 0xc66ad1ee63b457047e7102425e657b70105f5eb9
(5) 0xfab642ee1cbacd8fc678c83e821f7d8beda61fec
(6) 0xf76e1c57250b88c1628430d0c04e3b4ecb111c0e
(7) 0xf4994bfce769c16f1631f0609867858a96885917
(8) 0xf31105aee2b095265ea46c51e2644eacbab96cb7
(9) 0x51213b5aa72783e7216b55fc2ecb3104dfd5f465

Private Keys
==================
(0) 77b92fa8bdf4bec94f3ebf67f44fb11ff660911ca64d3aa2c729b689aa8c807b
(1) e1b555743af9cc58fb094349776f944b76ff85663b51d5d6bc4802da2e92c54c
(2) c5180d4154bb2d89eb89335766070dcc8210b25374ef8d71c26f50d002f3c450
(3) 61acc2eaf3fdcecad846cf0507ae8cc07fa03a9bf00a581974c268c6bcba0afd
(4) 7f384dad1148c73257c596bc875ca492e8c6e99bb5f7de6958ea4cfe82a5b9a3
(5) 9796225e8d81a3f72e4fccfe3a562838bf589d4c40fcadbdc85c9b9ad5d5ad4c
(6) b858608913552368f4bdbc33a01f7fc7ec98684b013eab2d8dcb696246cbea56
(7) 3b581c0f56aa9937706cd0e27e7a1ccd45513c71d845ab5b18ff5039c20e9d8a
(8) f5d548c0b0c9974711814937b2d0d8373e244aa265ac2e0174b2b9ec35faa134
(9) 22cb6ad0b97dda82426c04485fca580f25746602bc94950efcb13d10528bf622

HD Wallet
==================
Mnemonic:      marriage artwork corn dentist other feel decrease pride brass flash wire since
Base HD Path:  m/44'/60'/0'/0/{account_index}

Listening on localhost:8545

  • testrpc启动后自动建立了10个帐号(Accounts),与每个帐号对应的私钥(Private Key)。
  • 每个帐号中都有100个测试用的以太币(Ether)。
  • 要注意testrpc仅运行在內存中,因此每次重开时都会回到全新的状态。

建立项目

输入以下命令

luoxuedeMBP:~ luoxue$ cd desktop
luoxuedeMBP:desktop luoxue$ mkdir SmartContractDemo
luoxuedeMBP:desktop luoxue$ cd SmartContractDemo
luoxuedeMBP:SmartContractDemo luoxue$ mkdir hello
luoxuedeMBP:SmartContractDemo luoxue$ cd hello
luoxuedeMBP:hello luoxue$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
luoxuedeMBP:hello luoxue$ ls

目录结构:

  • /contracts:存放智能合约原始代码的地方
  • /migrations:这是 Truffle用来部署智能合约的功能,待会儿我们会修改2_deploy_contracts.js来部署 HelloWorld.sol。
  • /test: 测试智能合约的代码放在这里,支持js 与 sol 测试。
  • truffle.js: Truffle 的设置文档

新建HelloWorld.sol
放在contracts里,代码如下

pragma solidity ^0.4.4;

contract HelloWorld {
  function sayHello() returns (string) {
    return ("Hello World");
  }
}

编译
现在执行truffle compile命令,我们可以将HelloWorld.sol原始码编译成Ethereum bytecode。

luoxuedeMBP:hello luoxue$ cd build
luoxuedeMBP:build luoxue$ ls
contracts
luoxuedeMBP:build luoxue$ cd contracts
luoxuedeMBP:contracts luoxue$ ls
HelloWorld.json Migrations.json
  • 编译成功,新增了build文件夹,会在HelloWorld文件夹下面的build/contracts文件夹下面看见HelloWorld.json文件。


    罗韭菜的超详细dapp从零实战(二)-- 编写智能合约与truffle_第1张图片
    image.png

部署

  • 复制migration文件夹中的init文件,创建名为2_deploy_contracts.js的文件,代码如下:
var HelloWorld = artifacts.require("HelloWorld");
module.exports = function(deployer) {
  deployer.deploy(HelloWorld);
};
  • 使用artifacts.require语句来取得准备部署的合约。使用deployer.deploy语句将合约部署到区块链上。这边HelloWorld是contract的名称而不是文件名。因此可以用此语法读入任一.sol文件中的任一合约。

  • 现在执行truffle migrate命令

  • 注意!!!需要切换到truffle develop 网络下编译和部署,并且部署文件需要在编译前写对,因为编译即产生一个合约地址,错误的部署文件会对不上
    姿势如下:

luoxuedeMBP:HelloWorld luoxue$ truffle develop
省略
truffle(develop)> compile
Compiling ./contracts/HelloWorld.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

truffle(develop)> migrate
Using network 'develop'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xad8b447607866b32b1c115156a97f9d247a125d35c14585ac3ed3f9eaa06a528
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying HelloWorld...
  ... 0xae7215511d62acedac6c4880d8578240e73913373eaaf6d0e86253197b35261b
  HelloWorld: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
truffle(develop)> 

获取合约对象

  • 通过web3 来获取合约对象
  • 输入
// 声明一个对象
truffle(develop)> let contract;
undefined
// 实例化
// truffle console
truffle(develop)> HelloWorld.deployed().then(instance => contract = instance)

  • 解释:truffle console中预载了truffle-contract函数库,以方便操作部署到区块链上的合约。

  • 这边使用HelloWorld.deployed().then语句来取得HelloWorld合约的Instance(实例),并存到contract变量中,以方便后续的调用。

  • 使用的是js es6+语句

调用合约函数

truffle(develop)> contract.sayHello()
'Hello World'
  • 注意如果该函数没有constant 或者pure ,需要.call()
    如将代码增加一个函数无pure/constant如下:
pragma solidity ^0.4.4;

contract HelloWorld {
  // 能直接调用
  function sayHello() pure public returns (string) {
    return ("Hello World");
  }
  // 需要依靠.call调用
  function test() public returns (string) {
    return ("Hello World");
  }
}
  • 重新编译与部署, 注意部署时候需要加上-- reset
 // 编译
truffle(develop)> compile
Compiling ./contracts/HelloWorld.sol...

Compilation warnings encountered:

/Users/luoxue/Desktop/SmartContractDemo/HelloWorld/contracts/HelloWorld.sol:9:3: Warning: Function state mutability can be restricted to pure
  function test() public returns (string) {
  ^ (Relevant source part starts here and spans across multiple lines).

Writing artifacts to ./build/contracts
// 部署
truffle(develop)> migrate
Using network 'develop'.

Network up to date.
truffle(develop)> migrate --reset

正确的调用姿势

truffle(develop)> contract.sayHello()
'Hello World'
truffle(develop)> contract.test.call()
'Hello World'
truffle(develop)> 
  • 输入与输出,在代码里面加入一个echo函数,输入字符串,返回输出
function echo(string s) public returns (string) {
    return s;
  }
truffle(develop)> contract.echo.call("melody")
'melody'

你可能感兴趣的:(罗韭菜的超详细dapp从零实战(二)-- 编写智能合约与truffle)