Aprendizaje rápido-votación simple DApp

Votación simple DApp

A continuación, tenemos que comenzar a crear una DApp, aunque es una aplicación de votación muy simple, pero contendrá el flujo de trabajo completo y la página interactiva. Los pasos principales para construir esta aplicación son los siguientes:

  1. Primero instalamos una cadena de bloques simulada llamada ganache, que permite que nuestro programa se ejecute en el entorno de desarrollo.
  2. Escriba un contrato y despliegue a ganache.
  3. Luego interactuaremos con ganache a través de la línea de comando y la página web.

La forma en que nos comunicamos con blockchain es a través de RPC (Llamada de procedimiento remoto). web3js es una biblioteca de JavaScript que abstrae todas las llamadas RPC para que pueda interactuar con la cadena de bloques a través de JavaScript. Otro beneficio es que web3js le permite crear excelentes aplicaciones web utilizando su marco de JavaScript favorito.

Preparación para el desarrollo-Linux

La siguiente es una guía de instalación basada en Linux. Esto requiere que instalemos nodejs y npm por adelantado, y luego instalemos ganache-cli, web3 y solc con npm para continuar con el siguiente paso del proyecto.

mkdir simple_voting_dapp
cd simple_voting_dapp
npm init
npm install ganache-cli web3@0.20.1 solc
node_modules/.bin/ganache-cli

Si la instalación es exitosa, ejecute el comando node_modules / .bin / ganache-cli, debería poder ver el resultado que se muestra en la figura a continuación.
Inserte la descripción de la imagen aquí
Para facilitar las pruebas, ganache creará 10 cuentas por defecto, cada cuenta tiene 100 éter. . Debe usar una de las cuentas para crear una transacción, enviar y recibir ether.

Por supuesto, también puede instalar la versión GUI de ganache en lugar de la versión de línea de comandos, descargue la versión GUI aquí: http://truffleframework.com/ganache/

Contrato de solidez

Escribiremos un contrato llamado Voting, este contrato tiene el siguiente contenido:

  • Un constructor solía inicializar algunos candidatos.
  • Un método para votar (agregue 1 al número de votos)
  • Un método para devolver el número total de votos obtenidos por el candidato.

Cuando implementa un contrato en la cadena de bloques, se llama al constructor, y solo una vez. A diferencia de todos los códigos implementados en el mundo web que sobrescribirán el código anterior, el contrato implementado en la cadena de bloques es inmutable, es decir, si actualiza el contrato y lo implementa nuevamente, el contrato anterior seguirá existiendo en la cadena de bloques Y los datos siguen ahí. El nuevo despliegue creará una nueva instancia del contrato.

Código y explicación

pragma solidity ^ 0.4 .22;
contract Voting {
	mapping(bytes32 => uint8) public votesReceived;
	bytes32[] public candidateList;
	constructor(bytes32[] candidateNames) public {
		candidateList = candidateNames;
	}

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

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

Línea 1. Debemos especificar qué versión del compilador compilará el código

La asignación de línea 3. es equivalente a una matriz o diccionario asociativo, que es un par clave-valor. La clave de asignación de votos recibidos es el nombre del candidato, y el tipo es bytes32. El valor de la asignación es un número entero no asignado, que almacena el número de votos.

Línea 4. En muchos lenguajes de programación (como el diccionario <HashTable heredado del diccionario> en java y python), todos los nombres de los candidatos solo se pueden obtener mediante votesReceived.keys. Sin embargo, no existe un método de este tipo en la solidez, por lo que debemos administrar por separado un conjunto de candidatos candidatosLista.

Línea 14. Tenga en cuenta que votesReceived [key] tiene un valor predeterminado de 0, por lo que no necesita inicializarlo a 0, solo agregue 1 directamente.

También notará que cada función tiene un especificador de visibilidad (como public en este ejemplo). Esto significa que las funciones pueden llamarse desde fuera del contrato. Si no desea que nadie más llame a esta función, puede convertirla en una función privada. Si no especifica la visibilidad, el compilador lanzará una advertencia. El compilador de solidez ha realizado algunas mejoras recientemente: si el usuario olvida marcar la función privada y la función privada se puede llamar externamente, el compilador detectará este problema.

También verá una vista de modificador en algunas funciones. Por lo general, se usa para decirle al compilador que la función es de solo lectura (es decir, el estado de la cadena de bloques no se actualiza cuando se llama a la función).

A continuación, utilizaremos la biblioteca solc instalada en la sección anterior para compilar el código. Si recuerdas, mencionamos antes que web3js es una biblioteca que te permite interactuar con blockchain a través de RPC. Utilizaremos esta biblioteca para implementar contratos en la consola del nodo e interactuar con la cadena de bloques.

Compilar el contrato

In the node console> Web3 = require('web3')
> web3 = new Web3(new
Web3.providers.HttpProvider("http://localhost:8545"));
> web3.eth.accounts
['0x5c252a0c0475f9711b56ab160a1999729eccce97'
'0x353d310bed379b2d1df3b727645e200997016ba3']
> code = fs.readFileSync('Voting.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)

Primero, ejecute el nodo en el terminal para ingresar a la consola del nodo, inicialice el objeto web3 y consulte la cadena de bloques para obtener todas las cuentas.

Asegúrese de que ganache ya se esté ejecutando en otra ventana

Para compilar el contrato, primero cargue el código de Voting.sol y asócielo a una variable de tipo cadena, y luego compile el contrato como se muestra a la derecha.

Cuando compila con éxito el contrato, imprima el objeto compiledCode (puede ver el contenido directamente ingresando el compiledCode en la consola del nodo), notará que hay dos campos importantes, son muy importantes, debe comprender:

  1. compiledCode.contracts[':Voting'].bytecode:Este es el código de bytes después de compilar Voting.sol. También es el código que se implementará en la cadena de bloques.
  2. compiledCode.contracts[':Voting'].interface: Esta es una interfaz o plantilla de contrato (llamada definición abi), que le dice al usuario qué métodos hay en este contrato. Siempre que desee interactuar con cualquier contrato en el futuro, necesitará esta definición abi. Puede leer más sobre ABI aquí. En proyectos futuros, utilizaremos el marco de trufas para gestionar la compilación y la interacción con blockchain.

Sin embargo, antes de usar cualquier marco, es útil tener una comprensión profunda de cómo funciona, porque el marco abstraerá estos contenidos.

Contrato de implementación

Continuemos el curso y ahora implementemos el contrato en la cadena de bloques. Para hacer esto, primero debe crear un objeto de contrato VotingContract pasando la definición abi. Luego use este objeto para implementar e inicializar el contrato en la cadena.

Execute this in your node console:
> abiDefinition = 
JSON.parse(compiledCode.contracts[':Voting'].interface)
> VotingContract = web3.eth.contract(abiDefinition)
> byteCode = compiledCode.contracts[':Voting'].bytecode
> deployedContract = 
VotingContract.new(['Alice','Bob','Cary'],{data: byteCode, from: 
web3.eth.accounts[0], gas: 4700000})
> deployedContract.address
'0x0396d2b97871144f75ba9a9c8ae12bf6c019f610'
// Your address will be different
> contractInstance = VotingContract.at(deployedContract.address)

VotingContract.new implementa el contrato en la cadena de bloques.
El primer parámetro es una serie de candidatos: los candidatos competirán por las elecciones, lo cual es fácil de entender. Veamos qué hay en el segundo parámetro:

  1. datos: este es el código de bytes que implementamos en la cadena de bloques después de la compilación.
  2. from: La cadena de bloques debe rastrear quién implementó este contrato. En este caso, somos solo la primera cuenta devuelta de llamar a web3.eth.accounts como la cuenta que implementó este contrato. Recuerde, web3.eth.accounts devuelve una serie de 10 cuentas de prueba creadas por ganache. Antes de operar, debe tener esta cuenta y desbloquearla. Al crear una cuenta, se le pedirá que ingrese una contraseña, que es lo que utiliza para demostrar su propiedad de la cuenta. En la siguiente sección, lo presentaremos en detalle. Por conveniencia, ganache desbloqueará 10 cuentas por defecto.
  3. gas: cuesta dinero interactuar con blockchain. Este dinero se usa para pagar a los mineros, porque lo ayudan a incluir el código en la cadena de bloques. Debe especificar cuánto está dispuesto a gastar para incluir su código en la cadena de bloques, que es establecer el valor de "gas". El saldo de ETH en su cuenta "de" se usará para comprar gasolina. El precio del gas lo establece la red. Hemos implementado el contrato y tenemos una instancia de contrato (variable contractInstance) que podemos usar para interactuar con el contrato.

Hay miles de contratos en la cadena de bloques. Entonces, ¿cómo reconocer que su contrato está en la cadena? La respuesta es encontrar la dirección del contrato implementado deployedContract.address. Cuando necesita interactuar con el contrato, necesita esta dirección de implementación y la definición abi de la que hablamos anteriormente.

Interacción de consola

In your node console: > contractInstance.totalVotesFor.call('Rama') { [String: '0'] s: 1, e: 0, c: [ 0 ] } > contractInstance.voteForCandidate('Rama', {from:
web3.eth.accounts[0]})
'0xdedc7ae544c3dde74ab5a0b07422c5a51b5240603d31074f5b75c0ebc78
6bf53'
> contractInstance.voteForCandidate('Rama', {from:
web3.eth.accounts[0]})
'0x02c054d238038d68b65d55770fabfca592a5cf6590229ab91bbe7cd72da
46de9'
> contractInstance.voteForCandidate('Rama', {from:
web3.eth.accounts[0]})
'0x3da069a09577514f2baaa11bc3015a16edf26aad28dffbcd126bde2e71f
2b76f'
>
contractInstance.totalVotesFor.call('Rama').toLocaleString()'3
'

{[String: '0'] s: 1, e: 0, c: [0]} es la notación científica del número 0. El valor devuelto aquí es un objeto bigNumber, puede usar su método .toNumber () Para mostrar los números:

contractInstance.totalVotesFor.call('Alice').toNumber()
	web3.fromWei(web3.eth.getBalance(web3.eth.accounts[1]).toNumber(),'ether'
)

Los valores de BigNumber se almacenan en formato decimal de coma flotante en forma de símbolos, exponentes y coeficientes. s es el símbolo de signo, es decir, positivo y negativo; e es el exponente exponente, lo que indica que hay varios ceros después del bit más alto; c es el coeficiente de coeficiente, que es el número significativo real; el número de parámetros de entrada del constructor de bignumber está limitado a 14, La representación del coeficiente es una matriz que se intercepta de atrás hacia adelante, con 14 bits interceptados una vez. Vote por el candidato y vea el número de votos para continuar el curso, llame a los métodos voteForCandidate y totalVotesFor en su consola de nodos y vea los resultados.

Cada vez que vote por un candidato, obtendrá una identificación de transacción: por ejemplo: ' 0xdedc7ae544c3dde74ab5a0b07422c5a51b5240603d31074f5b75c0ebc786bf53'. Esta identificación de transacción es la credencial de la transacción, y puede hacer referencia a esta transacción en cualquier momento en el futuro. Esta transacción es inmutable. Para una cadena de bloques como Ethereum, la inmutabilidad es una de sus características principales. En el próximo capítulo, utilizaremos esta función para crear aplicaciones.

Interacción de página web

En este punto, la mayor parte del trabajo se ha completado. Lo que aún tenemos que hacer es crear un html simple con el nombre del candidato y llamar al comando de votación (lo hemos probado en la consola de nodejs). Puede encontrar el código html y el código js a la derecha. Colóquelos en el directorio del capítulo 1 y abra index.html en un navegador.

index.html

<!DOCTYPE html>
<html>
	<head>
		<title>
			Voting DApp
		</title>
		<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/boot
		strap.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/gh/ethereum/web3.js/dist/web3.mi
	n.js">
	</script>
	<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js">
	</script>
	<script src="./index.js">
	</script>

</html>

Consejos:

  1. <head>Introduzca la biblioteca de tipo css de bootstrap en forma de enlace. Las siguientes clases, como container, table-responsive, etc., son todas de bootstrap
  2. <th>Celda de encabezado de tabla, celda de tabla, la celda después del nombre del candidato es el número de votos, se distingue por id para facilitar la escritura, luego la relación correspondiente se escribe en js
  3. <input>Un cuadro de entrada, define la identificación para facilitar el valor en js
  4. <a>El botón btn en forma de hipervínculo, href = "#" es un salto a esta página, es decir, sin salto; onclick apunta al método en js. Para simplificar el proyecto, hemos codificado el nombre del candidato. Si lo desea, puede ajustar el código para seleccionar dinámicamente candidatos.

index.js

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
abi = JSON.parse('[{"constant":false,…}]') VotingContract = web3.eth.contract(abi);
contractInstance = VotingContract.at('0x329f5c190380ebcf640a90d06eb1db2d68503a53');
candidates = {
	"Alice": "candidate-1",
	"Bob": "candidate-2",
	"Cary": "candidate-3"
};
function voteForCandidate(candidate) {
	candidateName = $("#candidate").val();
	try {
		contractInstance.voteForCandidate(candidateName, {
			from: web3.eth.accounts[0]
		},
		function() {
			let div_id = candidates[candidateName];
			$("#" + div_id).html(contractInstance.totalVotesFor.call(candidateName).toString());
		});
	} catch(err) {}
}
$(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);
	}
});

En la línea 4, reemplace la dirección del contrato en el código con su propia dirección del contrato. La dirección del contrato es la dirección de contrato previamente implementada

Si todo va bien, debería poder ingresar el nombre del candidato en el cuadro de texto, y luego el número de votos debería incrementarse en 1.
Nota: debido a razones de red, web3.js puede no estar disponible, puede descargarlo a la importación local.

Si puede ver la página, vote por el candidato y luego vea el aumento en el número de votos, entonces el primer contrato se ha creado con éxito, ¡felicidades! Todos los votos se guardan en la cadena de bloques y son inmutables. Cualquiera puede verificar independientemente cuántos votos recibió cada candidato. Por supuesto, todas nuestras cosas se hacen en una blockchain simulada (ganache). En las siguientes lecciones, implementaremos este contrato en la cadena pública real. En la Parte 2, implementaremos el contrato en una cadena pública llamada Ropsten testnet, y también aprenderemos cómo usar el marco de trufas para crear contratos y administrar dapps.

Para resumir, esto es lo que ha hecho hasta ahora:

  1. Al instalar node, npm y ganache, ha configurado el entorno de desarrollo.
  2. Codifica un contrato de votación simple, lo compila y lo implementa en la cadena de bloques.
  3. Interactuó con la página web y el contrato a través de la consola de nodejs.
2146 artículos originales publicados · Me gusta 2405 · Visita 240,000+

Supongo que te gusta

Origin blog.csdn.net/weixin_42528266/article/details/105528554
Recomendado
Clasificación