En esta página puedes encontrar las códigos en Solidity (de Ethereum) de un contrato inteligente para poder compilar y desplegar un sistema de voto en un simulador de blockchain (vía Ganache js). La prueba del resultado se puede hacer vía consola o a través de navegador (con los códigos html y js).
Instalación de los paquetes necesarios
Instalación Linux
Instalación Windows
Instalación Mac Os
sudo apt-get updatecurl -sL https://deb.nodesource.com/setup_7.x -o nodesource_setup.shsudo bash nodesource_setup.shsudo apt-get install nodejsnode --versionnpm --versionmkdir -p tallerUPVcd tallerUPVnpm install ganache-cli web3@0.20.1 solc@0.4.23node_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 updatebrew install nodejsnode --versionnpm --versionmkdir -p tallerUPVcd tallerUPVnpm install ganache-cli web3@0.20.1 solc@0.4.23node_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); } });