智能合约开发

在这个入门教程中咱们将创建以太坊智能合约开发一个应用的环境并学习开发一个投票类智能合约。咱们将构建一个简单的"Hello World!" 应用程序, 这是一个投票应用程序。node

该应用程序很是简单,它所作的只是初始化一组候选人,让任何人投票给候选人,并显示每一个候选人收到的总票数。linux

我有意避免使用任何DAPP框架构建这个应用程序,由于框架抽象掉不少细节,你不了解系统的内部。此外,当你使用框架时,将对框架所作的繁重工做有更多的体会!web

1. 设置智能合约开发环境

咱们使用一个模拟的内存区块链(ganache)代替真实的区块链在进行开发。在本教程的2章,咱们将与真实的区块链交互。下面是安装ganache、web3js的步骤,而后在linux上启动一个测试链。在macOS上安装过程也是同样的。npm

智能合约开发

你能够看到ganache-cli自动建立了10个测试帐号,每一个帐号预分配了100(虚构的)ethers编程

2.开发简单的投票智能合约

咱们将使用solidity编程语言来开发咱们的智能合约。若是您熟悉面向对象编程,学习用solidity开发合约应该是垂手可得的事。咱们将开发一个合约对象,含有一个构造函数初始化候选人数组。合约对象有2个方法:数组

  1. 返回候选人得到的总票数
  2. 增长候选人的投票数。

注意:构造函数只被调用一次,当您部署智能合约到区块链。不像在网络世界里的每个部署你的代码覆盖旧的代码,部署后的代码在区块链上是不变的。例如,若是你更新你的合约而且再次部署,旧合约仍然会在区块链上, 它所存储的数据不受影响,新的部署将建立一个新实例的合约。网络

下面是投票合约的代码:架构

pragma solidity ^0.4.18;  
    // We have to specify what version of compiler this code will compile with  
      
    contract Voting {  
      /* mapping field below is equivalent to an associative array or hash.  
      The key of the mapping is candidate name stored as type bytes32 and value is  
      an unsigned integer to store the vote count  
      */  
        
      mapping (bytes32 => uint8) public votesReceived;  
        
      /* Solidity doesn't let you pass in an array of strings in the constructor (yet).  
      We will use an array of bytes32 instead to store the list of candidates  
      */  
        
      bytes32[] public candidateList;  
      
      /* This is the constructor which will be called once when you  
      deploy the contract to the blockchain. When we deploy the contract,  
      we will pass an array of candidates who will be contesting in the election  
      */  
      function Voting(bytes32[] candidateNames) public {  
        candidateList = candidateNames;  
      }  
      
      // This function returns the total votes a candidate has received so far  
      function totalVotesFor(bytes32 candidate) view public returns (uint8) {  
        require(validCandidate(candidate));  
        return votesReceived[candidate];  
      }  
      
      // This function increments the vote count for the specified candidate. This  
      // is equivalent to casting a vote  
      function voteForCandidate(bytes32 candidate) public {  
        require(validCandidate(candidate));  
        votesReceived[candidate] += 1;  
      }  
      
      function validCandidate(bytes32 candidate) view public returns (bool) {  
        for(uint i = 0; i < candidateList.length; i++) {  
          if (candidateList[i] == candidate) {  
            return true;  
          }  
        }  
        return false;  
      }  
    }

复制上面的代码,在hello_world_voting目录下建立一个Voting.sol文件。如今让咱们来编译代码并将其部署到ganache的区块链上.app

为了编译solidity代码,咱们须要安装名字为solc的npm模块框架

~/hello_world_voting$ npm install solc

咱们将在node控制台中使用这个库来编译咱们的合约。在上一篇文章中咱们提到,web3js是一个让咱们能够经过rpc访问区块链的库。咱们将使用该库来部署咱们的应用程序并与之交互。

首先,在命令行中断运行node命令进入node控制台,初始化solc和文本对象。下面的全部代码片断都须要在node控制台中键入

~/hello_world_voting$ node  
> Web3 = require('web3')  
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

为了确保web3对象已经初始化、区块链可以访问,让咱们试一下查询区块链上的全部帐户。您应该看到以下的结果:

> web3.eth.accounts  
    ['0x9c02f5c68e02390a3ab81f63341edc1ba5dbb39e',  
    '0x7d920be073e92a590dc47e4ccea2f28db3f218cc',  
    '0xf8a9c7c65c4d1c0c21b06c06ee5da80bd8f074a9',  
    '0x9d8ee8c3d4f8b1e08803da274bdaff80c2204fc6',  
    '0x26bb5d139aa7bdb1380af0e1e8f98147ef4c406a',  
    '0x622e557aad13c36459fac83240f25ae91882127c',  
    '0xbf8b1630d5640e272f33653e83092ce33d302fd2',  
    '0xe37a3157cb3081ea7a96ba9f9e942c72cf7ad87b',  
    '0x175dae81345f36775db285d368f0b1d49f61b2f8',  
    '0xc26bda5f3370bdd46e7c84bdb909aead4d8f35f3']

从voting.sol加载代码,保存在一个字符串变量中,而后开始编译

> code = fs.readFileSync('Voting.sol').toString()  
> solc = require('solc')  
> compiledCode = solc.compile(code)

当你的代码编译成功并打印了合约对象的内容(在node控制台中输出的内容),有2个字段很重要,须要理解它们:

  • compiledCode.contracts[‘:Voting’].bytecode: Voting.sol源代码编译后获得的字节码。这是将被部署到blockchain的代码。
  • compiledCode.contracts[‘:Voting’].interface: 合约接口或模板(称为ABI)告诉用户合约含有哪些方法。