Los Contratos Inteligentes son bloques de construcción de la tecnología blockchain. Mientras muchos desarrolladores usan lenguajes populares como Solidity, hay otra forma de escribir contratos inteligentes: usar opcodes. En esta guía para novatos explicaremos cómo escribir, probar y desplegar un contrato inteligente usando sólo opcodes.
¿Qué son los Opcodes y Por Qué Usarlos?
Opcodes, corto para códigos de operación (operation codes), son instrucciones básicas que la Máquina Virtual de Ethereum (Ethereum Virtual Machine, EVM) entiende. Pueden parecer complejas pero ofrecen beneficios únicos:
1: Conocimiento Profundo del EVM
Trabajar directamente con Opcodes provee un conocimiento profundo sobre cómo la EVM opera y ofrece conocimiento que puede ser invaluable para los desarrolladores, investigadores y educadores.
¿2: Optimización de Gas?
Los Opcodes permiten a los desarrolladores tener la habilidad de optimizar el código para la eficiencia de gas, reduciendo los costos de la transacción.
3: Funcionalidad Personalizada
Los Opcodes permiten un nivel de personalización y control que puede que no se logre a través de lenguajes de alto nivel. Los desarrolladores pueden hacer funcionalidades específicas, de acuerdo a sus requerimientos únicos.
4: Análisis de Seguridad
Examinando el bytecode de un contrato, los auditores y expertos de seguridad pueden identificar vulnerabilidades y asegurar que el contrato se comporte como debe.
Guía Paso a Paso sobre Cómo Escribir un Contrato Inteligente Usando Opcodes
Escribir contratos inteligentes usando opcodes puede ser abrumador pero, desglosemos la tarea y aprendamos cómo podemos desplegar nuestro primer contrato inteligente usando opcodes.
1: Entendiendo los Opcodes EVM
Entender los opcodes es el primer paso. Hay cerca de 120 opcodes, cada uno con diferentes funcionalidades. Aquí hay algunos ejemplos:
Para aprender más sobre opcodes, puedes revisar esta guía completa. Practica usando la EVM playground para familiarizarte con los opcodes.
2: Escribe el Opcode para el Contrato Inteligente
Ahora que estás cómodo con los opcodes, esboza la lógica de tu contrato. Determina qué funciones quieres realizar y cómo los datos serán almacenados y manipulados.
Para esta guía, vamos a escribir un opcode muy simple para invocar dos números.
Así es como se ve:
PUSH1 0X02
PUSH2 0X03
ADD
Vamos a simplificar estas líneas:
-
PUSH1 0x02
empuja el valor0x02
al stack -
PUSH1 0x03
empuja el valor0x03
al stack -
ADD
estalla los dos valores superiores desde el stack, los junta y empuja el resultado al stack.
3: Calcula el Bytecode para el Opcode
Una vez tengamos el opcode para nuestro contrato. Entendamos cómo podemos calcular el bytecode para el opcode dado:
- PUSH 0x02
-
PUSH1
El opcode paraPUSH1
es0x60
-
0x02
El valor a ser empujado al stack - Combinado, esto da el bytecode
0x6002
- PUSH1 0x03
-
PUSH1
: El opcode paraPUSH1
es0x60
. -
0x03
: El valor a ser empujado al stack. - Combinado, esto da el bytecode
0x6003
.
- ADD
-
ADD
: El opcode deADD
es0x01
. - No hay un valor asociado, así que el bytecode simplemente es
0x01
.
Juntando todo esto, el bytecode completo para los opcodes dados es:
0x6002600301
Este bytecode puede ser usado para desplegar o interactuar con un contrato en la red de Ethereum.
4: Despliega el contrato
Remix no provee una forma directa de compilar opcodes crudos. Así que vamos a usar un contrato wrapper el cual incluirá el bytecode como constructor. Esto nos permitirá desplegar los opcodes.
Aquí está cómo se vería nuestro contrato wrapper:
pragma solidity ^0.8.0;
contract DeployOpcodes {
uint256 public sum;
constructor() {
deployOpcodes();
}
function deployOpcodes() private {
assembly {
let x := mload(0x40) // Encuentra el lugar de almacenamiento vacío
mstore(x, 0x02) // Primer número a añadir
mstore(add(x, 0x20), 0x03) // Segundo número a añadir
let result := add(mload(x), mload(add(x, 0x20))) // Sum the numbers
sstore(sum.slot, result) // Almacena el resultado en el estado de la variable "sum"
}
}
function getSum() public view returns (uint256) {
return sum;
}
}
En este contrato, tenemos varios componentes claves:
Declaración del Contrato **
DeployOpcodes
:** Este es el nombre de nuestro contrato y es donde alojaremos todas las funciones y variables relacionados a nuestro despliegue de opcodes.Función Privada **
deployOpcodes
:** Dentro de esta función, vamos a trabajar directamente con la Máquina Virtual de Ethereum (EVM) usando el lenguaje assembly. Aquí hay un desglose de qué hace cada línea:
a. Bloque de Asamblea: Empezamos con el keyword
assembly
, permitiéndonos escribir códigos EVM de bajo nivel.b. Encontrar una Ubicación para de Almacenamiento Vacío: La línea
let x := mload(0x40)
carga el valor de la ubicación de la memoria0x40
, un lugar especial en la EVM que usualmente contiene el “puntero de memoria libre”. Asignando este valor a la variablex
, encontraremos una ubicación de almacenamiento vacío.c Almacenar el Primer Número: Luego,
mstore(x, 0x02)
almacena el valor0x02
en la ubicación de la memoria apuntado porx
. Esto representa el primer número a añadir.d Almacenar el Segundo Número: La línea
mstore(add(x, 0x20), 0x03)
almacena el valor0x03
en la ubicación de la memoriax + 0x20
. Esto representa el segundo número a añadir.e Calcular la Suma: Con
let result := add(mload(x), mload(add(x, 0x20)))
, cargamos los valores en las ubicaciones de la memoriax
yx+0x20
, juntarlos y asignar el resultado a una variable llamadaresult
.f Almacenar el Resultado: Finalmente,
sstore(sum.slot, result)
almacena el valorresult
en la ranura de almacenamiento correspondiente al estado de la variablesum
. Esto nos permite retirar la suma luego.
¡Ahora usar Remix es fácil! ¡Compila el código y luego pulsa el botón Deploy!
Puedes ver que tenemos la función getSum, el cual nos retornará el valor 5.
Así es como escribimos nuestros contratos inteligentes usando opcodes.
Escribir contratos inteligentes usando opcodes no sólo es un ejercicio académico; es una herramienta poderosa para los desarrolladores que quieran optimizar, personalizar y realmente entender sus contratos inteligentes.
Si encontraste esta guía útil, ¡por favor dame un aplauso y sígueme para tener más conocimiento!
Pari Tomar (Twitter, LinkedIn)
Este artículo es una traducción de Pari Tomar, hecha por Héctor Botero. Puedes encontrar el artículo original aquí.
Sería genial escucharte en nuestro Discord, puedes contarnos tus ideas, comentarios, sugerencias y dejarnos saber lo que necesitas.
Si prefieres puedes escribirnos a @web3dev_es en Twitter.
Discussion (0)