nodejs的版本必须大于8.0.0
点击下载node
命令行指定淘宝镜像
npm --registry https://registry.npm.taobao.org info underscore
配置后可通过下面方式来验证是否成功
npm config get registry
或者
npm info express
在线的remix-solidity IDE编辑器
点击编写智能合约
彩票项目代码如下:
pragma solidity ^0.4.17; //指定solidity的版本
contract Lottery{
address public manager; //管理员地址
address[] public players; //投注者(玩家)地址
address public winner; //赢家(中奖者)地址
//构造函数 指定管理员地址为合约部署者的地址
function Lottery() public{
manager = msg.sender;
}
//拿到管理员的地址 view字段表示该操作对智能合约没有任何改变
function getManager() public view returns (address){
return manager;
}
//投注彩票 每注彩票1ether(可自行设置)
function enter() public payable {
require(msg.value == 1 ether);
players.push(msg.sender);
}
//返回所有的投注彩票的人
function getAllPlayers() public view returns (address[]){
return players;
}
//获取智能合约账户的余额 即奖池的奖金
function getBalance() public view returns(uint){
return this.balance;
}
//获取参加博彩项目的玩家人数
function getPlayersCount() public view returns(uint){
return players.length;
}
//产生一个随机数 据此决出中奖者
function random() private view returns (uint){
return uint(keccak256(block.difficulty, now, players));
}
//决出中奖者 并将奖池奖金全部发送到其账户
function pickWinner() public onlyManagerCanCall {
uint index = random() % players.length;
winner = players[index];
players = new address[](0) ; //将奖池玩家清空 便于下一轮游戏的开始
winner.transfer(this.balance);
}
//如果由于特殊原因游戏中止 则将奖池奖金退还给所有玩家
function refund() public onlyManagerCanCall{
for(uint i = 0; i < players.length; i++){
players[i].transfer(1 ether);
}
players = new address[](0) ; //将奖池玩家清空 便于下一轮游戏的开始
}
//只有管理员才能进行操作 关键字段modifier
modifier onlyManagerCanCall(){
require(msg.sender == manager);
_;
}
}
1、solidity编译器,编译环境
2、 mocha 抹茶测试环境
3、部署智能合约的脚本 到指定网络
npm init
一直yes即可
开发环境的目录结构:
npm install --save solc
//编译的脚本 compile.js
const path = require('path');
const fs = require('fs');
const solc = require('solc'); //引入solidity编译器 -> solc相当于javac
//找到智能合约所在的路径
const srcpath = path.resolve(__dirname, 'contracts', 'Lottery.sol');
//读取智能合约的源代码 utf-8
const source = fs.readFileSync(srcpath, 'utf-8');
//编译智能合约 生成两部分内容 1.bytecode字节码 2.便于调用的应用程序二进制接口(即ABI) interface
const result = solc.compile(source, 1);
//将智能合约暴露出去 便于调用
module.exports = result.contracts[':Lottery'];
导入web3js
web3js简介:web3js是以太坊提供的一个javascript库,封装了以太坊的RPC通信API,提供了一系列与区块链交互的方法,使得javacsript与以太坊交互变得简单。
web3js与以太坊节点的交互,其底层用的是jsonRPC,不过web3js屏蔽了复杂的编码解码过程,提供了更易用的接口。
npm install --save web3
npm install --save ganache-cli
npm install --save mocha
这里只测试其中一部分功能(test.lottery.js)
const assert = require('assert'); //引入assert框架
const ganache = require('ganache-cli'); //引入ganache
const Web3 = require('web3'); //引入Web3
const web3 = new Web3(ganache.provider()); //设置测试的provider
const {interface, bytecode} = require('../compile');
let lottery; //智能合约
let accounts; //账户
//获取智能合约实例
beforeEach(async ()=>{
accounts = await web3.eth.getAccounts();
lottery = await new web3.eth.Contracts(JSON.parse(interface))
.deploy({
data:bytecode
}).send({
from:accounts[0],
gas:'1000000'})
});
//测试智能合约地址是否存在
describe('彩票智能合约',()=>{
it('部署智能合约',()=>{
//断言
assert.ok(lottery.options.address);
}) ;
//问你自己问题, 我们关心的业务是什么?
//1.测试彩票投注
it('一个账户投注彩票', async()=>{
await lottery.methods.enter().send({
from:accounts[0],
value:web3.utils.toWei('1','ether');
});
});
const players = await lottery.methods.getPlayers().call({
from:accounts[0]
});
//断言
assert.equal(accounts[0], players[0]);
assert.equal(1, players.length);
});
it('多个账户投注彩票', async()=>{
await lottery.methods.enter().send({
from:accounts[0],
value:web3.utils.toWei('1','ether');
});
await lottery.methods.enter().send({
from:accounts[1],
value:web3.utils.toWei('1','ether');
});
await lottery.methods.enter().send({
from:accounts[2],
value:web3.utils.toWei('1','ether');
});
});
const players = await lottery.methods.getPlayers().call({
from:accounts[0]
});
assert.equal(accounts[0],players[0]);
assert.equal(accounts[1],players[1]);
assert.equal(accounts[2],players[2]);
assert.equal(3,players.length);
});
//确定只有给正确钱才能买到彩票 测试失败的情况
it('只有给正确钱才能买到彩票', async()=>{
try{
await lottery.methods.enter().send({
from:accounts[0],
value:web3.utils.toWei('0.1','ether');
});
assert(false);
}catch(err){
//代码应该执行到这里
assert.equal(1,1);
}
});
});
//3.测试调用修饰符,只有经理可以开奖,测试正常的逻辑和错误的逻辑
// 4. 测试整个彩票投注流程, 投注,开奖,奖池清空一个人投注,直接开奖,那这个人应该得奖.
npm install --save truffle-hdwallet-provider@0.0.3
通过infura提供的以太坊节点将智能合约部署上去
//部署智能合约到真实的rankeby网络 deploy.js
const Web3 = require('web3');
const {interface,bytecode} = require('./compile');
const HDWalletProvider = require('truffle-hdwallet-provider');
const mnemonic = "crouch fiction income edge cluster turtle plastic ozone mom predict goddess express";
const provider = new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/b5193966085f4ae0a469a7a77215b0ba");
const web3 = new Web3(provider);
deploy =async ()=>{
//获取账户
const accounts = await web3.eth.getAccounts();
//打印accounts[0],即管理员的地址
console.log(accounts[0]);
//result即为智能合约实例
const result = await new web3.eth.Contract(JSON.parse(interface))
.deploy({
data:bytecode
//如果构造函数有参数 可以进行添加 arguement:[]
}).send({
from:accounts[0], //指定从哪个账户扣费
gas:'3000000'
});
//打印智能合约的地址
console.log('address:' + result.options.address);
console.log('------------------'); //分割线
//打印智能合约的abi 通过abi和地址可以获取该智能合约实例 然后进行调用
console.log(interface);
};
deploy();
import Web3 from 'web3'; //引入的1.0版本d的web3
const web3 = new Web3(window.web3.currentProvider); //安装了Metamask的web3
export default web3;
//导入安装了用户provider的web3 通过这个调用彩票智能合约实例
import web3 from './web3'
const address = '0xb4858082B1A03069b09f0ff8E2992e2B3728810B';
const abi = [{"constant":true,"inputs":[],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"manager","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pickWinner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"player","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getManager","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"enter","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getAllPlayers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllPlayerCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}];
//生成彩票智能合约实例
const lottery = new web3.eth.Contract(abi, address);
//导出彩票智能合约实例 通过这个可以调用智能合约里面的方法
export default lottery;
import React, {Component} from 'react';
import {Message, Card, Image, Icon, Statistic, Button, Label} from 'semantic-ui-react';
import web3 from './web3';
import lottery from './lottery';
class App extends Component {
constructor(props){
super(props);
this.state={
manager:"",
balance:0,
players:0,
ck:false,
isManger:'none'
}
}
async componentDidMount(){
const address = await lottery.methods.getManager().call();
const balance = await lottery.methods.getBalance().call();
const players = await lottery.methods.getAllPlayerCount().call();
this.setState({
manager:address,
balance,
players,
});
let accounts = await web3.eth.getAccounts();
if(accounts[0] === address) {
this.setState({isManger:'inline'})
}else {
this.setState({isManger:'none'})
}
}
//点击购买彩票
enter = async () =>{
this.setState({ck:true});
const accounts = await web3.eth.getAccounts();
await lottery.methods.enter().send({
from:accounts[0],
value:'1000000000000000000'
});
this.setState({ck:false});
window.location.reload(true); //重新刷新页面
};
pickWinner= async ()=>{
this.setState({ck:true});
const account = await web3.eth.getAccounts();
await lottery.methods.pickWinner().send({
from:account[0]
});
this.setState({ck:false});
window.location.reload(true); //重新刷新页面
};
refund = async () =>{
this.setState({ck:true});
const account = await web3.eth.getAccounts();
await lottery.methods.refund().send({
from:account[0]
});
this.setState({ck:false});
window.location.reload(true); //重新刷新页面
};
render() {
console.log(web3.version);
return (
区块链博彩游戏
有胆你就来!
'/logo.jpg'/>
骗人彩
管理员地址:
每周日晚上8点整开奖
'red'>
{this.state.balance} e
奖池奖金
'user'/>
已有{this.state.players}人参与
);
}
}
export default App;