Solidity en Remix

Un poco más que un Hello World

Lautaro Barceló
Boske
6 min readMar 11, 2021

--

Solidity es un lenguaje de alto nivel orientado a Smart Contracts. Su sintaxis es similar a la de JavaScript y está enfocado específicamente a la Máquina Virtual de Ethereum (EVM).

Con Solidity se pueden escribir desde los contratos más sencillos (crowdfunding, votaciones, emisión de certificados, etc) hasta complejos mecanismos aplicables a casos concretos de comercio internacional en los que se precisen diversas firmas para liberar, modificar o cancelar el pago de acuerdo a las reglas explicitadas en el código.

Posible aplicación de Smart Contract.

Eso sí: todo tiene un costo. Debemos asegurarnos de que nuestro contrato no gaste más gas del que debería y utilizar blockchain eficazmente, solo en casos en que lo requiera o haga una diferencia hacerlo. No hace falta que el contrato en Solidity cargue los nombres y apellidos de cada uno de los involucrados en la cadena de suministro, u otros strings innecesarios. Para eso podemos recurrir a integers que son mucho más económicos. Todo gasta gas y más tarde encontraremos una forma de visualizar esos integers de una forma más legible.

Antes de profundizar más en cada una de estas cuestiones, vamos a proporcionar algunos ejemplos de Smart Contracts en el entorno Remix.

Remix es un entorno integrado de desarrollo (IDE) basado en un navegador que integra un compilador y un entorno en tiempo de ejecución para Solidity sin los componentes orientados al servidor.

Allí vamos a poder desarrollar y poner a prueba nuestros Smart Contracts de la forma más real posible. Incluso tendremos a nuestra disposición address ficticias cargadas con gas para poder así simular transacciones antes de llevar nuestro código a la aplicación. Remix también admite extensiones convierten tu Smart Contract en una dApp customizable o incluir el lenguaje de programación orientado a contratos Vyper, basado en Python.

Vamos a empezar por abrir el compilador de Remix y donde dice File Explorers, iniciar un nuevo archivo con extension “.sol”. En nuestro caso iniciamos un archivo nuevo llamado “prueba.sol”.

Para hacer nuestro primer Smart Contract en Solidity imaginemos la siguiente situación: tras un examen, el docente a cargo debe calificar a sus alumnos y certificar que hayan aprobado el curso utilizando Blockchain. Para ello solo precisa de sus respectivas address. Los alumnos que saquen una nota mayor a 4 estarán aprobados, mientras que los que saquen una nota menor permanecerán desaprobados y deberán ser reevaluados.

Un contrato para Solidity es una colección de código (sus funciones) y datos (su estado) que residen en una dirección específica en la blockchain de Ethereum. Los Contratos en Solidity son similares a las clases de los lenguajes orientados a objetos. Cualquier contrato puede contener declaraciones del tipo variables de estado, funciones, modificadores de función, eventos, structs y enums. Además, los contratos pueden heredar de otros contratos.

pragma solidity ^0.5.9;contract Examen {}

Ya tenemos entre llaves nuestro primer contrato (todavía vacío). En la primera línea de código tenemos que incluir la versión de Solidity que estamos usando, el ^ indica que en todas las versiones posteriores a la definida, el código puede ser ejecutado sin problemas.

Dentro de las llaves de Examen, vamos a utilizar el siguiente código:

    
uint8 constant minNota public = 4;

struct Alumno {
bool corregido;
bool aprobado;
uint8 nota;
}

Primero vamos a declarar una variable de estado global y otras más dentro de una struct.

Las variables de estado son valores que están permanentemente almacenados en una parte del contrato conocida como storage del contrato.

Dado que la nota mínima a saber es un 4, vamos a utilizar un tipo de variable uint8. Un uint8 no tiene signo y cuenta con solo 8 bits, así que para números pequeños y constantes es la mejor opción. Nótese que también la visibilidad de la variable está expresada después de su nombre, en este caso es ‘public’. Con esto nos aseguramos que Solidity cree un getter, es decir, algún mecanismo que nos permita acceder al valor desde el contrato. Suponiendo que los alumnos quieren saber cual es la nota mínima para evitar el aplazo, no está mal dejarlo en público.

Las Structs son tipos definidos por el propio usuario y pueden agrupar múltiples variables

A continuación encontramos un struct que, como dice su definición, agrupa dos variables booleanas y una nueva variable ‘nota’. Le damos el nombre de ‘Alumno’ ya que ahí almacenaremos el valor de las variables que nos dirán si el alumno aprobó o no aprobó el examen.

Address: Contiene un valor de 20 bytes (tamaño de una dirección de Ethereum). Los tipos address también tienen miembros y sirven como base para todos los contratos.

Tipos mapping: son declarados como mapping(_KeyType => _ValueType). Aquí _KeyType puede ser casi cualquier tipo excepto mapping, un array de tamaño dinámico, un contrato, un enum y un struct. _ValueType puede ser cualquier tipo, incluyendo mappings.

Lo siguiente que haremos es declarar una nueva variable de estado del tipo address, que nos va a servir para designar al ‘owner’ de este contrato. En este caso el ‘owner’ es el docente, por lo cual vamos a ver más adelante cómo hacer para designar al ‘owner’ apenas llama al contrato.

En segundo lugar, realizamos un mapping entre la struct ‘Alumno’ antes mencionada y una address. La función del mapping es similar a la de un diccionario en Python o sus análogos en otros lenguajes orientados a objetos. Podríamos referirnos a la nota de un alumno con ‘alumnos[address].nota’. Gracias a hacer público el mapping, obtenemos un getter que nos va a servir más adelante para poder ver el estado de cada alumno con solo ingresar su address desde la interfaz de Remix.


address public owner;

mapping (address => Alumno) public alumnos;

El constructor es una función opcional declarada con la keyword ‘constructor’ que se ejecuta al crear el contrato, y donde se puede ejecutar el código de inicialización del mismo.

Antes de que el contrato se ejecute, las variables de estado se inicializan a su valor especificado si las inicializas inline, o a cero si no lo haces.

La address de la persona que se conecta al contrato está almacenada en ‘msg.sender’. Al utilizar un constructor, podemos iniciar las variables anteriormente declaradas en algún valor. Dado que el constructor solo se ejecuta la vez que se crea el contrato, ‘msg.sender’ tendrá distinto valor al conectarse un estudiante con el contrato desde otra address. No puede haber más de un constructor en el contrato y su uso es opcional, desde ya que es muy útil por poder asegurarnos un estado inicial, pero no siempre es necesario.

Por último vamos a crear la función ‘ponerNota’.

Las funciones son las unidades ejecutables del código dentro de un contrato.

Además de los argumentos, vamos a querer que la función sea pública para poder acceder a ellos desde la interfaz y así agregar cada una de las notas. Para ello necesitamos dos argumentos: el address que identifica a cada alumno, y su nota. En segundo lugar vamos a utilizar la función ‘require’ que sirve para poner una condición antes de continuar con la ejecución. En este caso queremos que solamente el docente (owner) tenga acceso a esta función, así que con esta condición logramos que cualquier ‘msg.sender’ que se conecte al contrato y no sea el creador del mismo (asignado previamente en el construct) vea un error y no pueda continuar.

El mapping nos servirá para acceder a los diferentes values dentro de cada par y cambiar su valor. Por último, la cláusula ‘if’ decidirá si el examen está o no aprobado.

function ponerNota(address idAlumno, uint8 nota) public {
require(msg.sender == owner);
alumnos[idAlumno].corregido = true;
alumnos[idAlumno].nota = nota;
if (alumnos[idAlumno].nota >= minNota) {
alumnos[idAlumno].aprobado = true;
}
}

El código debería verse de este modo:

Código completo en https://github.com/lauutt/boske/blob/main/examen.sol

Llegó la hora de probarlo. En el video a continuación hay una demostración del código corriendo en Remix. Para testear el código contamos con la VM Javascript que ejecutará el programa directamente desde nuestro browser. Una vez que generamos una nueva instancia del contracto haciendo click en Deploy, vemos cómo podemos desde ellas acceder a los getters y funciones. Remix nos otorga unas cuantas address para testing cargadas con suficiente gas como para probar todo lo que se nos ocurra.

En el video podemos ver como el Owner es capaz poner varias notas a sus alumnos. ¿Qué pasará si un alumno quiere cambiarse la nota o quiere puntuar a algunos de sus compañeros?

--

--

Lautaro Barceló
Boske
Writer for

Estudiante de IA y 日本語, desarrollador y productor musical. Llenando la incompletitud esencial.