Instalación de los paquetes necesarios
Instalación Linux
Instalación Windows
Instalación Mac Os
sudo apt-get update
curl -sL https://deb.nodesource.com/setup_7.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install nodejs
node --version
npm --version
mkdir -p tallerUPV
cd tallerUPV
npm install ganache-cli web3@0.20.1 solc@0.4.23
node_modules/.bin/ganache-cli
- Instalar Visual Studio Community Edition. Es necesario como mínimo tener todo lo relacionado con Visual C++.
- Instalar Windows SDK for Windows.
- Instalar Python 2.7. Asegúrate que está en el PATH (sino pincha aquí).
- Instalar git añadiéndolo de nuevo al PATH.
- Instalar OpenSSL. Asegúrate de elegir el paquete adecuado (según tu arquitectura) y elige la instalación completa. No cambies la ruta predefinida para la instalación.
- Descarga e instala node v8.1.2.
- En un terminal escribe y ejecuta el comando npm install ganache-cli web3@0.20.1 solc@0.4.23
- Desde el terminal ve a la carpeta node_modules/.bin y escribe y ejecuta ganache-cli.cmd
En primer lugar instala Homebrew: https://brew.sh/. Este paquete te ayudará a instalar otros paquetes directamente desde el terminal.
brew update
brew install nodejs
node --version
npm --version
mkdir -p tallerUPV
cd tallerUPV
npm install ganache-cli web3@0.20.1 solc@0.4.23
node_modules/.bin/ganache-cli
Ya tenemos las 10 cuentas de Ethereum
Available Accounts ================== (0) 0x2c7f38aca10ec0fd14ed7f35af3ad39c913b8d64 (1) 0x2ae9d31105deed46940aa02a9de6d0d150ee6226 (2) 0xeb7e61354d0617048299141bc6a1153888a2dc69 (3) 0x72d88e13efd3f19e93bee8b0ce02963a5f66db53 (4) 0x085aea284a40fa25eb4ae218e1ee5c943ee62260 (5) 0xcece14d68ca6263d7b647bd1405e17d447a4c680 (6) 0x4041074e2ad96f726ce900fd260ca78f175f3305 (7) 0x49ac44fb83b1665b159a306f01db67cd3e3b0a91 (8) 0xd6b289ae3a3c5bc16ad969cd4e668a6a591848e6 (9) 0x639a91e56f09ca7037ed25ecb2f3070704701af4 Private Keys ================== (0) e3b8caba48c0cfe7566fadf2e3b860f84f6c03c4afc081faa3e2860839aadcb2 (1) 9a0b5d7cc2f456a09c9437a8b7d23c99451f1a39d4da4727c7996fcd1f6ffb7b (2) 4d1743ff5922d11615337db0f5c5029aa9727a4fd41e3e3f0f66eea800204751 (3) 9e37a55e14ff76058f0ccb4bb917fd71cd1dab18c5f306328a195813c8d15a39 (4) 12f34bcbaa1578b8fd4b30ec3d617a6e15dfca2919602c7be5f98c3e33770661 (5) d2fcaec8a58bebdb4b9591f0416eaf883fd001fd3d634482a8eb8d4548ec9f20 (6) b8b1e69a3408c2ea2b57f6491bd810b3097fb63ad85f23354b39bf0eafe563f5 (7) 72fe6c02eb15fb86855896933cb827ceae5b2a5064a01c3fdd62196fb43bd61c (8) 2f6d10d0a2bba1678efff1090722e848ee139bf4e6eae6e96a692d3efc59f7a2 (9) d3529a058c1b239125e0ad415141c8480cc8c4b40810271ac498d759dc9362fc
Contrato inteligente: VotoUPV.sol
pragma solidity ^0.4.18;
contract VotoUPV {
mapping (bytes32 => uint8) public votosRecibidos;
bytes32[] public listaCandidatos;
function VotoUPV(bytes32[] nombreCandidatos) public {
listaCandidatos = nombreCandidatos;
}
function totalVotosPara(bytes32 candidato) view public returns (uint8) {
require(candidatoValido(candidato));
return votosRecibidos[candidato];
}
function votoParaCandidato(bytes32 candidato) public {
require(candidatoValido(candidato));
votosRecibidos[candidato] += 1;
}
function candidatoValido(bytes32 candidato) view public returns (bool) {
for(uint i = 0; i < listaCandidatos.length; i++) {
if (listaCandidatos[i] == candidato) {
return true;
}
}
return false;
}
}
Compilando el contrato
node > Web3 = require('web3')
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
> web3.eth.accounts
> code = fs.readFileSync('VotoUPV.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)
Desplegando el contrato
> abiDefinition = JSON.parse(compiledCode.contracts[':VotoUPV'].interface)
> VotoUPVContract = web3.eth.contract(abiDefinition)
> byteCode = compiledCode.contracts[':VotoUPV'].bytecode
> deployedContract = VotoUPVContract.new(['Herve','Pep Lluis','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
> deployedContract.address
'0xeb85d153f6da07c2a9caa64032fc32a8e8b9067f' <- ESTA SERÁ LA DIRECCIÓN DEL CONTRATO
> contractInstance = VotoUPVContract.at(deployedContract.address)
Probando el contrato...a mano
> contractInstance.totalVotosPara.call('Herve')
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
> contractInstance.votoParaCandidato('Herve', {from: web3.eth.accounts[0]})
'0xdedc7ae544c3dde74ab5a0b07422c5a51b5240603d31074f5b75c0ebc786bf53'
> contractInstance.votoParaCandidato('Herve', {from: web3.eth.accounts[0]})
'0x02c054d238038d68b65d55770fabfca592a5cf6590229ab91bbe7cd72da46de9'
> contractInstance.votoParaCandidato('Herve', {from: web3.eth.accounts[0]})
'0x3da069a09577514f2baaa11bc3015a16edf26aad28dffbcd126bde2e71f2b76f'
> contractInstance.totalVotosPara.call('Herve').toLocaleString()
'3'
... y desde la web: index.html
<!DOCTYPE html>
<html>
<head>
<title> DApp Asegurando la participación ciudadana</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>DApp Asegurando la participación ciudadana con BlockChain. TechFest 2018 UPV</h1>
<div class="table-responsive">
<table class="table table-bordered">
<thead> <tr>
<th>Candidato</th>
<th>Número de votos</th>
</tr>
</thead>
<tbody>
<tr>
<td>Herve</td>
<td id="candidate-1"></td>
</tr>
<tr>
<td>Pep Lluis</td>
<td id="candidate-2"></td>
</tr>
<tr>
<td>Jose</td>
<td id="candidate-3"></td>
</tr>
</tbody>
</table>
</div>
<input type="text" id="candidato" />
<a href="#" onclick="votoParaCandidato()" class="btn btn-primary">Pincha para votar</a>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="./index.js"></script>
</html>
...index.js
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
abi = JSON.parse('
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"listaCandidatos","outputs":
[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},
{"constant":false,"inputs":
[{"name":"candidato","type":"bytes32"}],"name":"votoParaCandidato","outputs":
[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":
[{"name":"candidato","type":"bytes32"}],"name":"totalVotosPara","outputs":
[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":
[{"name":"candidato","type":"bytes32"}],"name":"candidatoValido","outputs":
[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":
[{"name":"","type":"bytes32"}],"name":"votosRecibidos","outputs":
[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":
[{"name":"nombreCandidatos","type":"bytes32[]"}],"payable":false,"stateMutability":
"nonpayable","type":"constructor"}]')
VotoUPVContract = web3.eth.contract(abi);
contractInstance = VotoUPVContract.at('0xeb85d153f6da07c2a9caa64032fc32a8e8b9067f');
candidatos = {"Herve": "candidate-1", "Pep Lluis": "candidate-2", "Jose": "candidate-3"}
function votoParaCandidato() {
nombreCandidato = $("#candidato").val();
contractInstance.votoParaCandidato(nombreCandidato,
{from: web3.eth.accounts[0]}, function() {
let div_id = candidatos[nombreCandidato];
$("#" + div_id).html(contractInstance.totalVotosPara.call(nombreCandidato).toString());});
$(document).ready(function() {
nombreCandidatos = Object.keys(candidatos);
for (var i = 0; i < nombreCandidatos.length; i++) {
let name = nombreCandidatos[i]
let val = contractInstance.totalVotosPara.call(name).toString()
$("#"+candidatos[name]).html(val); } });