前期准备
- 编辑器
理论上讲任何编辑器都可以编写Solidity合约代码,比如:WebStorm,VSCode,Sublime等。我选择atom
autocomplete-solidity代码自动补齐
linter-solium、linter-solidity代码错误检查
language-ethereum支持Solidity代码高亮以及Solidity代码片段 - 环境
node.js
开发框架:truffle(用react box)
安装truffle 
$ npm install -g ethereumjs-testrpc truffle
创建项目
luoxuedeMacBook-Pro:~ luoxue$ cd desktop
luoxuedeMacBook-Pro:desktop luoxue$ mkdir voting
luoxuedeMacBook-Pro:desktop luoxue$ cd voting
luoxuedeMacBook-Pro:voting luoxue$ truffle unbox react-box
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
  Compile:              truffle compile
  Migrate:              truffle migrate
  Test contracts:       truffle test
  Test dapp:            npm test
  Run dev server:       npm run start
  Build for production: npm run build
- 
项目结构
image.png - contracts:编写智能合约的文件夹,所有的智能合约文件都放置在这里
 - migrations:部署合约配置的文件夹
 - src:基于React的Web端源码
 - test:智能合约测试用例文件夹
 
编写智能合约
- 在contracts文件夹下创建Voting.sol文件
 - 编译环境: remix-online (remix.ethereum.org)
 - 创建合约对象Voting,存candidtae,bytes23[]是可变的
 
contract Voting{
    
    
   // luo
   // xue
   // ll
   // xx
   // mm
   
   
   bytes32[] candidates = new bytes32[](5);
}
- 构造函数
 
 function Voting(bytes32[] _candidates) public{
        
        for(uint i =0; i<_candidates.length;i++){
            candidates[i] = _candidates[i];
        }
        
    }
- 创建一个字典:候选人-》票数
 
mapping(bytes32 => uint) candidatesVotingCount;
- 创建投票方法
 
 function votingToPerson(bytes32 person) public {
        candidatesVotingCount[person]+=1;
       }
- 检查是否是合法的候选人
 
    function isValidPerson(bytes32 person) constant internal returns(bool){
        for(uint i = 0; i<candidates.length; i++){
            if(candidates[i] == person){
                return true;
            }
        }
        return false;
    }
- 完整版
 
pragma solidity ^0.4.4;
contract Voting{
    
    
   // luo
   // xue
   // ll
   // xx
   // mm
   
   // ["luo","xue","ll","xx","mm"]
   bytes32[] candidates = new bytes32[](5);
   
   mapping(bytes32 => uint)candidatesVotingCount;
   
   function Voting(bytes32[] _candidates) public {
       for(uint i =0; i<_candidates.length;i++){
           candidates[i] = _candidates[i];
       }
   }
   
   function votingToPerson(bytes32 person) public {
        assert(isValidPerson(person));
        candidatesVotingCount[person]+=1;
       }
       
    function votingTotalToPerson(bytes32 person) constant public returns (uint) {
        return candidatesVotingCount[person];
    }
    
    function isValidPerson(bytes32 person) constant internal returns(bool){
        for(uint i = 0; i<candidates.length; i++){
            if(candidates[i] == person){
                return true;
            }
        }
        return false;
    }
   }
   
- 
remix 检查调用情况
image.png
image.png - 
复制粘贴并更换掉simple sample.sol 替换成voting
image.png - 
在migration换掉部署文件中相应部分
image.png 编译Voting.sol
打开truffle控制台
$ truffle develop
编译合约

image.png
发现build文件夹里多了一个 voting.json文件

image.png
- 
App.js里面 改json的import
image.png 改this.state里面的状态,存储候选人相关信息
constructor(props) {
    super(props)
    this.state = {
      canddidates:[
        {
          name:"luo",
          count:0,
          id:101
        },
        {
          name:"xue",
          count:0,
          id:102
        },
        {
          name:"ll",
          count:0,
          id:103
        },
        {
          name:"xx",
          count:0,
          id:104
        },
        {
          name:"mm",
          count:0,
          id:105
        }
      ],
- 
改路由
image.png - 
与链上交互
通过get web3交互
注:
=>是个js 的箭头函数
this.instantiateContract() 初始化合约
image.png - 
修改合约初始化,获取合约实例
image.png - 
取到候选人的票数
image.png 
看控制台输出:
两个1票3个0票

image.png
- 
修改状态机, 让网页上显示合约上的票数
image.png - 
写修改函数,注意参数不用var 定义变量
image.png - 在remix里投票,看网页上也有实时变化
 - 
加投票按钮
image.png - 
从input 里获取资料,ref
image.png
从name里获得了input的value
把contract变成全局变量
在点击button里面调用
image.png
但要注意,这里from 的要用web3来调用 - 
然后刷新票数,直接复制上面即可
image.png 















