Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

Primeros pasos con Smart Contracts

¿Qué son los Smart Contracts?

En pocas palabras un Smart Contract es código ejecutable que corre sobre una Blockchain, básicamente escribimos código y lo desplegamos en una transacción y el código queda dentro de la Blockchain, para siempre.

Una forma de verlo es como un objeto que tiene un estado entonces una vez que el Smart Contract está en la Blockchain ese estado (entendiendo como estado a el conjunto de valores de los atributos de un objeto en un momento dado) no se puede alterar porque al estar grabado en una transacción en la Blockchain es inalterable.

La forma de alterarlo es generando una nueva transacción (invocando algunas de las operaciones del Smart Contract) de este modo si lo que hacemos cambia el estado del Smart Contract se generará una nueva transacción con el nuevo estado, otra vez, para siempre.

Al igual que una Blockchain que usamos para guardar datos y a medida que modificamos, por ejemplo, el estado de nuestra cuenta se genera una nueva transacción con el nuevo estado (al estilo libro de balances) lo único que podemos hace es conocer el historial de lo que fue pasando, cómo se modificó a través del tiempo pero no modificar lo existente sino que solo podemos generar un nuevo estado.

Lo mismo pasa con los Smart Contracts, si tengo un objeto que por ejemplo almacena un contador, cada vez que invoque la operación “incrementarContador” del Smart Contract lo que va a ocurrir es que se generará una nueva transacción (que tendrá un costo en GAS) con el nuevo estado, pero nunca podremos alterar el pasado.

Esto puede ser confuso, pero vamos a intentar verlo con ejemplos en breve.

¿Cómo hago para crear y probar un Smart Contract?

He hecho algunos videos al respecto, pero lo cuento brevemente acá otra vez.

Test RPC

Test RPC es una Blockchain en memoria, compatible con Ethereum, es decir, soporta Smart Contracts (el estándar de facto al menos), y como es en memoria es inmediato, además de que no consumimos GAS real ni hay que esperar a que las transacciones se confirmen, entonces es una gran forma de aprender, en general nuestro flujo de trabajo será:

  • Desarrollar y probar con Test RPC
  • Probar sobre TestNet (que es una red Ethereum real pero para hacer pruebas)
  • Desplegar en la red productiva

Hay otras cosas que vamos a poder hacer gracias a Test RPC como por ejemplo unit testing a nuestros Smart Contracts, pero eso lo dejamos para más adelante, comencemos por lo básico

¿Cómo programo un Smart Contract?

La forma más común de hacerlo es programando en un lenguaje de alto nivel llamado Solidity (si bien hay alternativas), compilar y desplegar los bytecodes en la Blockchain, eso es lo que vamos a hacer ahora mismo paso a paso.

Solidity

Solidity es similiar a Javascript en su sintaxis pero es tipado, así que nos va a resultar bastante familiar su uso, hay un par de formas de poder compilar y desplegar un contrato

  • Utilizar un compilador online
  • Utilizar VSCode y un plugin
  • Utilizar cualquier editor y Truffle
  • Otros

Nostros vamos a usar VSCode y Truffle que es bastante cómodo y nos va a servir además de para compilar, para hacer Unit test e incluso desplegar.

Truffle

Truffle es un framework, es decir, un conjunto de herramientas, tiene varias cosas

  • Compilador Solidity
  • Posibilidad de ejecutar Unit test tipo Jassmine
  • Capacidad de desplegar a cualquier cliente RPC, como Test RPC o una Blockchain como Ethereum

Entonces, instalando Test RPC y Truffle tenemos todo lo que necesitamos para desarrollar nuestros Smart Contracts sin más.

Como casi todo en este mundo de hoy en día hace falta tener NodeJs para instalar tanto Test RPC como Truffle, además de otras cosas.

Ahora si, comenzamos a escribir un contrato

Una vez terminada la sección “instalar cosas varias horas” estamos listos para escribir el primer contrato, la idea es hacer todo el flujo, para que se puedan relacionar las ideas y queden claros los conceptos.

Los primero que vamos a hacer es usar Truffle para crear un proyecto de ejemplo, eso nos va a ayudar con varias de las tareas de creación de scripts de deploy y testing, etc., vamos al directorio donde queremos crear nuestro proyecto y hacemos

truffle init

después de un momento abrimos con VSCode haciendo

code .

después iniciamos Test RPC y listo, vemos el proyecto creado por Truffle con varios archivos, vamos a ver un poco de qué se trata

Untitled

Apenas ejecutamos Test RPC nos da alguna información, vamos a las cuentas (remarcadas en amarillo) y el último mensaje que indica en qué puerto está escuchando, que es el puerto por defecto al que Truffle envía mensajes, de momento nada que hacer para que funcione. Veamos qué generó Truffle por nosotros.

 

vscode

Ok, como dije Truffle genera todo un “entorno” de trabajo, es decir, además de un contrato de ejemplo (que probaremos en breve) genera algunas otra cosas, como por ejemplo Unit Tests y mecanismos para publicar el contrato en una Blockchain, en nuestro caso Test RPC.

En este caso vamos a centrarnos en la carpeta “contracts” allí pondremos se encuentran los contratos creados por Truffle a modo de demo y pondremos los nuestros en el futuro, vamos a abrir Metacoin.sol que es el que nos interesa.

pragma solidity ^0.4.4;

contract MetaCoin {
	mapping (address => uint) balances;

	// Constructor del contrato, se ejecuta solo cuando el contrato es desplegado
	// en la Blockchain por primera vez
	function MetaCoin() {
		balances[tx.origin] = 10000;
	}

	// Ejecuta una transferencia, modifica los valores del mapping del contrato
	// por lo tanto modifica su estado, requiere una transacción y consumen GAS
	function sendCoin(address receiver, uint amount) returns(bool sufficient) {
		if (balances[msg.sender] < amount) return false;
		balances[msg.sender] -= amount;
		balances[receiver] += amount;
		return true;
	}

	// Retorno el valor del mapping en una posición particular
	// no ejecuta ninguna transacción, es inmediato
	function getBalance(address addr) returns(uint) {
		return balances[addr];
	}
}

He simplifica un poco el ejemplo que viene en el proyecto que genera Truffle pero es esencialmente lo mismo, también agregué algunos comentarios en el código, vamos a ver un poco de qué se trata.

En principio se trata de una meta-moneda, es decir, es decir, tendremos una cantidad de saldo en el contrato que se irá transfiriendo entre los participantes.

Primero, este contrato es en sí un objeto y se declara con la palabra clave contract.

Tiene tres funciones, por defecto todas públicas:

  • Metacoin: Es el constructor, y solo se ejecutará cuando se despliegue el contrato en la Blockchain, además vemos que se inicializa el mapping (un diccionario) con un valor de 10000 en el address de quien crea el contrato, esto es para que quien despliegue tenga esa balance la primera vez.
  • sendCoing: Realiza una transferencia entre cuentas, simplemente verifica que el balance de quien quiere enviar fondos sea suficiente y luego pasa el valor de un lado al otro. Notemos que en ambos casos se lee el address de quien invoca la función desde una variable de contexto llamada msg, que representa el mensaje hacia la Blockchain, dentro de él hay mucha información entre ésta el address de quien genera el mensaje. Notemos que modifica el diccionario balances por lo tanto altera el estado del contrato y por esto genera una nueva transacción en la Blockchain, esta operación no es inmediata.
  • getBalance: Simplemente retorna el valor en una dirección dada del mapping, notemos que no es más que una consulta, no modifica el estado del contracto, es decir, no genera una nueva transacción.

Compilar y desplegar nuestro contracto en Test RPC

Gracias a Truffle compilar y desplegar el contrato es bien simple (también ejecutar los Unit test, pero eso lo veremos después) no tenemos más que abrir el terminal integrado de VSCode y llamar a la consola de Truffle con el siguiente comando:

truffle console

y desde ahí podemos hacer varias cosas, empecemos compilando el contrato, para ello ejecutamos el siguiente comando

compile

de momento no demos importancia a los mensajes, vale decir que ha compilado tres cosas, nuestro contrato, una librería de utilidades y un contrato especial que genera Truffle para desplegar nuestro contrato (sí, raro, pero es así)

Bien, ahora tenemos el contrato generado, y además ha aparecido una carpeta build/contracts en el directorio del proyecto, ahí se encuentra lo que se va a desplegar en la Blockchain, vemos que son tres archivos json, uno por cada archivo Solidity que había en el directorio contracts

compile

Estos json contienen el abi del contrato (que es la metadata que permite saber cómo interactuar con el contrato) y el binario, vamos a desplegarlo en la Blockchain (TestRPC) y probar un par de cosas

Desplegando el contrato

Para desplegarlo no tenemos más que escribir en la consola

migrate

y listo, vemos un mensaje bastante largo de respuesta, entre los datos más importantes está el address del contrato (ya que ahora está en la Blockchain tiene una dirección) pero no nos preocupemos por copiar estos datos, Truffle ha actualizado los json que están en la carpeta buid/contracts con esta información.

Vamos a probar el contrato, así que vamos a usar varios comandos de Truffle para esto

Probando el contrato

Lo primero que vamos a hacer es generar un proxy al contrato, esto es, un objeto en javascript de nuestro lado (de lado cliente, quiero decir) que nos permita interactuar con el contrato sin necesidad de enviar mensajes RPC a mano (cosa que podríamos hacer pero esto es más simple) para esto lo que vamos a hacer es escribir lo siguiente

var coin;
MetaCoin.deployed().then(function(item) { coin = item;})

Básicamente Truffle nos permite acceder de manera sencilla al contracto desplegado con Metacoin.deployed, esto retorna una promesa (porque no es instantáneo) y ponemos la referencia en la variable coin.

Y si ahora hacemos

coin

Vemos un montón de información que no es otra cosa que el proxy al contrato con metadata y otras cosas, desde ahora vamos a interactuar con el contrato a través de esta variable coin.

Primero que nada, el constructor del contrato nos debería haber asignado 10000 a nuestro address (al elemento del diccionario con nuestro address como clave) ya que eso ocurre al ejecutar el constructor, pero nosotros no sabemos nuestro address, al principio vimos que TestRPC generaba un conjunto de address, podemos saber cuáles eran con Truffle, para esto escribimos

web3.eth.accounts

Y nos da todas las cuentas, para conocer la nuestra (la que estamos usando actualmente) el comando es

web.eth.coinbase

Y nos da un address, vamos a ponerlo en una variable para que sea más cómodo trabajar

var coinbase = web3.eth.coinbase

Ahora sí, vamos a invocar el contrato, primero lo más simple, conocer el saldo de nuestro address, para ello tenemos que invocar a getBalance y pasar el address que queremos conocer, en este caso el nuestro, así de simple

coin.getBalance.call(coinbase)

y nos retorna el valor, 1000, si consultamos la segunda cuenta en el array vemos que tiene 0

coin.getBalance.call(web3.eth.accounts[1])

Y es cero, en el diccionario interno que mantiene los balances de nuestro contracto el valor para este address es cero, vamos a transferir entonces

mirando el código del sendCoin vemos que recibe dos parámetros, el address de destino y el importe ya que quien genera la transacción (esta información se obtiene del contexto msg.sender) es quien transfiere al destino, en este caso como lo que vamos a hacer es modificar el estado del contrato (estamos alterando el contenido del diccionario que mantiene el balance) se va generar una transacción que tendrá un costo y demorará un tiempo (segundo o minutos dependiendo de la Blockchain y la confirmación de bloques) lo que vamos a hacer es usar sintaxis para leer el valor que retorna la promesa que devuelve la invocación, de este modo

 coin.sendCoin(web3.eth.accounts[1], 150).then(function(tx){console.log(tx)})

Esto demora un instante (en una Blockchain real será mucho más tiempo) y nos muestra el resultado de la transacción, para verificar si la transferencia funcionó consultamos nuevamente el balance de la cuenta destino

truffle(development)> coin.getBalance.call(web3.eth.accounts[1])
{ [String: '150'] s: 1, e: 2, c: [ 150 ] }

y vemos que tiene 150, por supuesto nuestro balance ahora es menor

coin.getBalance.call(coinbase)
{ [String: '9850'] s: 1, e: 3, c: [ 9850 ] }

con esto hemos logrado, compilar, desplegar y probar nuestro contrato, como dije estos nuevos valores (el estado del contrato) ya no se puede alterar, la forma de hacerlo es realizar otra operación que modifique su estado pero quedará todo el historial de cambios, porque es una Blockchain.

De este modo funciona un contrato inteligente, más adelante vamos a ver cómo hacer una aplicación web para acceder al contrato y otras cositas más.

Dejo un link con el ejemplo del contrato simplificado.

Nos leemos.

Loading