Desarrollo en Ethereum - 2. Estructura y elementos de un contrato

in solidity •  7 years ago  (edited)

Los contratos en Solidity se asemejan a las clases en lenguajes orientados a objetos tales como Java pero en vez de usar la palabra class, usamos la palabra reservada contract:

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    . . .
}

Uno de los contratos más simples que podemos encontrar es aquel que tiene una única variable de estado x y funciones get y set para leer y escribir respectivamente en dicha variable:

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    uint x;

    function set(uint _x) public {
        x = _x;
    }

    function get() public constant returns (uint) {
        return x;
    }
}

El código anterior contiene como primera línea el código pragma Solidity ^0.4.0. Esta línea indica al compilador que el código fue escrito para la versión 0.4.0 o siguientes pero inferiores a 0.5.0 de forma que nuevas versiones del compilador saben como tratar el código evitando comportamientos inesperados.

La variable x del contrato anterior es del tipo uint que describiremos posteriormente. Es posible que el contrato anterior contenga código que no entiendas ahora mismo pero no te preocupes, revisaremos cada tipo de elemento en éste y futuros artículos.

Si desplegáramos este contrato en la red de Ethereum, habríamos creado básicamente una pequeña “base de datos” con un campo x que cualquiera con acceso a la red podría leer y escribir.

Compilando nuestro contrato

Nuestro contrato puede ser escrito en cualquier editor de texto y guardado con extensión .sol para posteriormente ser compilado pero, ¿cómo compilamos nuestro contrato?

Aunque tenemos compiladores que podemos descargar e instalar en nuestro ordenador y que veremos en futuros artículos, Ethereum pone a nuestra disposición Remix, un compilador online de Solidity que nos es de gran utilidad para contratos sencillos y como forma de aprendizaje rápida.

Remix

Para acceder al compilador Remix visita la página https://remix.ethereum.org.

contrato1.png

Solo necesitas copiar el código de tu contrato en Remix y el código compilará automáticamente (siempre que la opción Auto compile esté habilitada) mostrando cualquier error de compilación que existiera en nuestro código:
contrato2.png

Si pinchas en Details puedes ver el código bytecode resultante de la compilación y que será lo que se envíe a la blockchain:
contrato3.png

Estructura de un contrato

Ahora que ya hemos escrito y compilado un contrato simple, veamos en detalle las distintas partes de las que puede constar un contrato. Dentro de un contrato podemos encontrar declaraciones de:

Variables de estado

  • Funciones
  • Modificadores
  • Eventos
  • Estructuras de datos
  • Tipos Enumerados

Solidity nos permite además que un contrato herede de otro contrato. Para los que no conozcan en que consiste la herencia en programación, la herencia es uno de los mecanismos de los lenguajes de programación orientada a objetos basados en clases, por medio del cual una clase se deriva de otra de manera que extiende su funcionalidad.

Variables de estado

Las variables de estado son valores que son almacenados de forma permanente en nuestro contrato. En nuestro anterior contrato, por ejemplo, x es una variable de estado que será guardada en la dirección Ethereum asociada a nuestro contrato y que podrá ser leída y escrita por usuarios y por otros contratos.

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    uint x;

}

La palabra uint define el tipo de nuestra variable. Si ya has programado en otros lenguajes sabrás que uint define una variable de tipo numérico no negativo, es decir, incluye el 0 y números enteros positivos. Además, la visibilidad o scope nos dice quién y desde donde se puede acceder a un elemento de un contrato. Dedicaremos un artículo complete a los diferentes tipos de variables así como la visibilidad de variables y funciones. Por ahora es suficiente con que sepas que es una variable de estado.

Funciones

Las funciones son unidades de código ejecutable dentro de un contrato. Siguiendo con el ejemplo anterior, nuestro contrato tenia las funciones get y set para leer y escribir en nuestra variable x.

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    uint x;

    function set(uint _x) public {
        x = _x;
    }

    function get() public constant returns (uint) {
        return x;
    }
}

Como vemos en el ejemplo, la función get nos devuelve un elemento de tipo uint que en este caso se corresponde a la variable x, y la función set no devuelve nada pero recibe un elemento de tipo uint que será el nuevo valor de x. Las funciones también tienen una visibilidad y en este caso se han definido como public. Además, la función get esta definida como constant para especificar que no modifica ninguna variable de estado en su interior.

Modificadores (de funciones)

Los modificadores se pueden usar para añadir o cambiar el comportamiento de funciones. Pueden utilizarse, por ejemplo, para comprobar de forma automática que una condición se cumple antes de ejecutar el código del contrato al que modifican:

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    uint x;
    address creador;

    function MiPrimerContrato() public{
        creador = msg.sender;
    }

    modifier soloCreador(){
        require(msg.sender == creador);
        _;
    }

    function set(uint _x) public soloCreador {
        x = _x;
    }

    function get() public constant returns (uint) {
        return x;
    }
}

El ejemplo de anterior incluye algunos conceptos nuevos. Se ha añadido una variable de estado creador que almacena la dirección del usuario que crea el contrato en la blockchain y que se inicializa en el constructor del contrato. El constructor es una función que se ejecuta de forma automática al crear el contrato. El constructor coge la dirección del usuario que envía la transacción (msg.sender) y la asigna a creador. Posteriormente se define un modificador con una condición para comprobar si la dirección que manda una transacción es igual a la dirección del creador. Por último, añadimos el modificador a la declaración de la función set. De esta forma, si alguien envía una transacción para modificar la variable x, la función comprobará en primer lugar si la transacción ha sido enviada por el creador del contrato.

En un modificador, el símbolo _; define donde será insertado el cuerpo de la función a la que se aplica el modificador. Así, en el ejemplo anterior, primero se insertará la condición del modificador y después el cuerpo de la función set.

Nota: require será explicado en futuros artículos. Por ahora vale con que sepas que comprueba una condición y lanza un error si no se cumple.

Eventos

Los eventos nos permiten saber cuando algo ha ocurrido desde el exterior. Imaginemos que queremos enterarnos de cuando alguien ha cambiado el valor de nuestra variable x. Para hacer esto, podríamos crear un evento en la función set:

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    uint x;

    event VariableModificada(address direccion, uint nuevoValor); // Evento

    function set(uint _x) public {
        x = _x;
        VariableModificada(msg.sender, _x);
    }

    function get() public constant returns (uint) {
        return x;
    }
}

Cualquiera podría entonces subscribirse a este evento y de esta forma ser notificados cuando el evento ocurra. Ésto nos evitaría tener que estar comprobando continuamente si el valor ha cambiado.

Estructuras

Las estructuras son tipos de datos personalizados que pueden agrupar varias variables.
Imagina que ahora no solo queremos almacenar el valor de x sino también el número de veces que ha sido modificada. Podemos crear una estructura con x y una variable nueva que lleve la cuenta de las veces que se modifica. Cada vez que se llama a la función set, el contador se incrementa:

pragma solidity ^0.4.0;

contract MiPrimerContrato { 

    struct Registro { // Struct
        uint x;
        uint cuenta;
    }

    Registro miRegistro;

    function set(uint _x) public {
       miRegistro.x = _x;
       miRegistro.cuenta = miRegistro.cuenta + 1;
    }

    function get() public constant returns (uint, uint) {
        return (miRegistro.x, miRegistro.cuenta);
    }
}

Tipos enumerados

Los tipos enumerados pueden ser usados para crear tipos personalizados con una conjunto finito de posibles valores.
Por ejemplo, podríamos tener un tipo predefino que nos diga si x ha sido modificada o no:

pragma solidity ^0.4.0;

contract MiPrimerContrato {
    enum EstadoVariable { Original, Modificada} // Enumerado
    
    uint x;
    EstadoVariable estado;

    function MiPrimerContrato() {
    estado = EstadoVariable.Original;
    }

    function set(uint _x) public {
        x = _x; 
    estado = EstadoVariable.Modificada;
    }

    function get() public constant returns (uint) {
        return x;
    }
}

Y con ésto acabamos este nuevo artículo en el que hemos aprendido la estructura y elementos de un contrato en Solidity, y hemos sido capaces de crear nuestros primeros contratos y compilarlos con Remix.

Puedes encontrar los ejemplos descritos en este artículo en GitHub.

Espero que te haya gustado y ¡hasta el próximo artículo!

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
https://aprendeblockchain.wordpress.com/desarrollo-en-ethereum/estructura-y-elementos-de-un-contrato/

Congratulations @asuarez! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Do not miss the last post from @steemitboard:

Are you a DrugWars early adopter? Benvenuto in famiglia!
Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Congratulations @asuarez! You received a personal award!

Happy Steem Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Do not miss the last post from @steemitboard:

Downvote challenge - Add up to 3 funny badges to your board
Vote for @Steemitboard as a witness to get one more award and increased upvotes!