あいつの日誌β

働きながら旅しています。

ブロックチェーンはじめました

あらすじ

スマートコントラクトからマネーのオイニーがしてきたので素振りしておきました。

やってみた

以下を参考にやってみた

Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 1 | by Mahesh Murthy | Medium

mkdir practice-dapp && cd $_
yarn init -y
yarn add solc --save
yarn add web3@0.20.6 --save
mkdir contracts script
touch contracts/Voting.sol script/vote.js

create contracts/Voting.sol

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;
  }
}

create script/vote.js

const fs = require('fs');
const solc = require('solc');
const Web3 = require("web3");

main();

function sleep(ms = 0) {
  return new Promise(r => setTimeout(r, ms));
}

async function main(err, blockchain) {

  // ganeche を起動しておく
  const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));

  // 登録済みのアカウントを確認
  const accounts = web3.eth.accounts;
  console.log(accounts);

  // compile 開始
  const code = fs.readFileSync('./contracts/Voting.sol').toString();
  const compiledCode = solc.compile(code);
  const abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface);
  const byteCode = compiledCode.contracts[':Voting'].bytecode;

  // deploy 開始
  const VotingContract = web3.eth.contract(abiDefinition);
  const deployedContract = VotingContract.new(
    ['Rama','Nick','Jose'],
    { data: byteCode, from: web3.eth.accounts[0], gas: 4700000 }
  )

  // deploy 中
  while (!deployedContract.address) {
    console.log("wait a minute...");
    await sleep(1000);
  }

  // deploy 完了
  console.log(deployedContract.address);

  // 投票開始
  const contractInstance = VotingContract.at(deployedContract.address)

  // 投票数を見る view なので gas を消費しない(transaction が発生しない)
  let result = contractInstance.totalVotesFor.call('Rama');
  console.log(result);

  // transaction が発生する
  contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]});
  contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]});
  contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]});
  result = contractInstance.totalVotesFor.call('Rama').toLocaleString();
  console.log(result);
}

感想

version 指定しないで yarn add web3 すると 1.0 の version をインストールするけどこれは不安定なのでお気をつけ下さい。 そして web3 の 0.2.x 系のドキュメントはここ

JavaScript API · ethereum/wiki Wiki · GitHub