手把手教你一步步开发第一个Dapp(使用solidity语言实现投票合约)——Remix版本

第一个Dapp开发(使用solidity语言实现投票合约)——Remix版本

写在前面:

现在流行的技术区块链算一个热门,我也在学习的路上,写下博客旨在为了记录一些自己遇到的问题和解决方法,希望可以多多帮助学习路上的小白。

提到区块链不得不提到比特币,但是现在热门的开发就是go语言开发和基于以太坊的开发,我目前在学的是以太坊的一些东西,之前没有接触很多,所以也是从无到有的过程。

经过这些天的学习我发现中国对于这块技术的讨论还是相对较少(在遇到问题的时候通过百度很难找出答案,不知道是因为大牛的封闭,还是我们确实缺乏这方面技术的研究)。

什么是Dapp?

App我们都知道是客户端应用,是application的简称。再说dapp就是D+app,d是英文单词decentralization的首字母,单词翻译中文是去中心化,即dapp为去中心化应用。主要强调的是一个可以被我们直观看见的一个页面这样子的应用,里面集成了我们的区块链技术(去中心化技术)。

自己很狗血的做了好久才稍微的明白了这个原理和工作的流程,但是学习的路上哪有一帆风顺,在你写出来东西的时候你就会有很大的成就感。

本篇通过标题也可以看出来主要是结合Remix这个强大的软件工具来进行第一个Dapp的开发,在后续我会再写一篇怎么通过Ubantu系统通过手动部署来实现第一个Dapp的实现。

目录

第一个Dapp开发(使用solidity语言实现投票合约)——Remix版本

1.项目准备

   1).安装浏览器

   2).安装MetaMask

   3).Remix

   4).安装Ganache软件

2.Remix基本操作(结合我们投票Dapp的开发)

 1)进入界面

2)基本介绍

3)智能投票合约

4)部署 & 执行交易

3.部署智能合约到Web

1)HTML:

 2)JS:

项目总结:


1.项目准备

首先开始项目的开发前我们需要做的前期准备有:

   1).安装浏览器

        推荐使用火狐,火狐上有第二步的钱包安装插件,所以建议使用火狐来开发你的以太坊。

   2).安装MetaMask

       在火狐浏览器上安装钱包MetaMask插件(可能需要小小的翻墙一下,安装结果如下所示,可以自己创建一个账号也可以选择看后面的教程)。

   3).Remix

        进入Remix网页编辑器:remix中文版 Remix英文版,这边分别提供了两种编译器供你选择,英文不好就选择中文版本。

   4).安装Ganache软件

       也需要翻墙,这个软件主要是用于产生是个账户来供我们使用,提供了区块链技术的可视化,在软件中可以本链上的区块个数,账号信息,账号私钥信息等等。

可以查看区块交易信息: 

注意:红框中的RPC SERVER在我们web部署的时候需要用到 

 前期的准备基本完成。有了简单易用的软件才是我们开启实践的第一步。

2.Remix基本操作(结合我们投票Dapp的开发)

 1)进入界面

    进入上面的网页编辑器(如下图所示):

2)基本介绍

     介绍基本的功能和操作:

3)智能投票合约

新建一个sol文件用来存放并写入我们的智能合约:

智能合约代码(代码不是我写的,还没学的那么深,能看懂就行,后续再学)

pragma solidity ^0.4.22;

contract Voting {

    bytes32[] public candidateList;
    mapping (bytes32 => uint8) public votesReceived;
    
    constructor(bytes32[] candidateNames) public {
        candidateList = candidateNames;
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    function totalVotesFor(bytes32 candidate) view public returns (uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    function validCandidate(bytes32 candidate) view public returns (bool) {
        for(uint8 i = 0; i < candidateList.length; i++) {
            if(candidateList[i] == candidate)
                return true;
        }
        return false;
    }
    
}

进行合约编译:

注意:其中的abi,我们集成到前端界面的时候会用到 

4)部署 & 执行交易

(一)部署

点击1处然后选择injected web3就会自动的跳出3界面,然后选择下一步就好了。这样就把你的合约部署的前面部分完成了。

连接成功就会如右下图所示账号会变化,核对即可(一般不会出错)

                                 

输入参数进行部署: 这个是构造函数那边的参数

["0xd4967590eb024589dfb6b9e48a576eb49ebc19d764b0d1d67dc21975e7258e97",
"0x416c696365000000000000000000000000000000000000000000000000000000",
"0x426f620000000000000000000000000000000000000000000000000000000000",
"0x4361727900000000000000000000000000000000000000000000000000000000",
"0x065e0be95fb43db528a20ba65c0e575e33cd4a9e1ca089dba4efff24596e8553"]

这其中的中间上个就是Alice,Bob,Cary的三个单词的bytes32形式,具体怎么转可以查看百度或者可以使用下面的软件进行转化: 字码装换

将该数据放入Deploy后面的输入框,就是构造函数的参数传递框。 

 点击Deploy                 出现  

确认即可,出现下面的数据就表示你把你的智能合约部署到我们的Ganache链上了。

 至此我们把合约部署的流程讲了一遍

(二)交易

我们做的是一个投票的合约,那么我们可以使用已经部署的合约进行调用函数,对其部署完成的合约进行展开,通过下图可以看见很多的细节,比如我们合约中的几个函数,一个是投票的函数(voteForCandidate),一个是统计票数的函数(totalVotesFor),我们可以对其验证是否像我们所期待的那样出现结果。

 首先查看票数,在totalVotesFor函数后面输入0x416c696365000000000000000000000000000000000000000000000000000000查看结果:可以看见出现了0

然后我们调用voteForCandidate对其投票后查看票数:左图显示当你调用投票函数的时候会叫你确认一笔交易,右图显示投完票后查看票数出现的结果(可以看见多出来了一票,证明了我们合约部署没有问题)

                                                                                                     

其他的函数可以自己去实践,至此我们的合约部署和调试就完成了

下面就是我们怎么把这个合约用到我们自己的网站上面去。 

3.部署智能合约到Web

首先先写一个简单的html界面,用于投票的可视化

1)HTML:

<!DOCTYPE html>
<html>
<head>
  <title>Hello World DApp</title>
  <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
</head>
<body class="container">
  <h1>A Simple Voting Application</h1>
  <div class="table-responsive">
    <table class="table table-bordered">
      <thead>
        <tr>
          <th>Candidate</th>
          <th>Votes</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Alice</td>
          <td id="candidate-1"></td>
        </tr>
        <tr>
          <td>Bob</td>
          <td id="candidate-2"></td>
        </tr>
        <tr>
          <td>Cary</td>
          <td id="candidate-3"></td>
        </tr>
      </tbody>
    </table>
  </div>
  <input type="text" id="candidate" />
  <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="./index.js"></script>
</html>

 2)JS:

web3 = new Web3(new Web3.providers.HttpProvider("HTTP://192.168.75.1:7545"));
abi = JSON.parse('[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]')
VotingContract = web3.eth.contract(abi);

//部署的合约地址 
contractInstance = VotingContract.at('0x5B15C032F8C8787815a73A2800560772196437Aa');

candidates = {"Alice": "candidate-1","Bob": "candidate-2","Cary":"candidate-3"}

function voteForCandidate() {
  //console.log(candidate);
  candidateName = $("#candidate").val();
  //console.log(candidateName);
  contractInstance.voteForCandidate(candidateName, {from: web3.eth.accounts[0]}, function() {
    let div_id = candidates[candidateName];
    console.log(contractInstance.totalVotesFor.call(candidateName).toString());
    $("#" + div_id).html(contractInstance.totalVotesFor.call(candidateName).toString());
  });
  console.log(contractInstance.totalVotesFor.call(candidateName).toString());
}

$(document).ready(function() {
  candidateNames = Object.keys(candidates);
  for (var i = 0; i < candidateNames.length; i++) {
    let name = candidateNames[i];
    let val = contractInstance.totalVotesFor.call(name).toString()
    $("#" + candidates[name]).html(val);
  }
});

 值得我们去研究的是js部分:

(一)js第一行引用了我们Ganache中的地址,详细可以看上面图片中的RPC SERVER。

(二)第二行是我们的abi,也看之前Remix中,复制就好了。

(三)合约地址需要我们去部署完以后的那个合约中复制。

经过修改就可以实现一个最简单的Dapp了

效果如下所示:

可以进行投票的测试,后期可以对页面进行美化。

项目总结:

这个Dapp的项目看起来很简单,但是其中会遇见很多的问题,不如你前端的webjs应用的版本不对,没有包含我们需要的方法,还有就是软件安装的问题会出现很多,你可能熟悉一个钱包的插件就要一天,然后熟悉Remix又需要一天的时间,所以当你遇到困难的时候慢慢学,当然学习的路上少不了学长的帮助。努力奋斗总是有结果的。

Remix函数部署输入的构造函数的参数必须是我上面的十六进制数,不然那就会出错,但是你web应用的时候又是可以将Alice直接输入进去。这个问题是Remix把它集成化了,我在Ubantu系统上手动部署的时候是没有问题的,直接输入Alice也可以直接部署,但是Remix就是不可以这样子部署,手动部署我下面会写一篇单独的文章来介绍。  

 整理不易多点关注+点赞+收藏,感谢各位大哥,持续关注后续更加精彩。

打个广告:代做Web毕设,专业团队值得信任,可以私聊。

No pains No Results 

猜你喜欢

转载自blog.csdn.net/weixin_45629315/article/details/113469323