Escrito por @espejelomar. Mándame un DM y aprenderemos juntos ?. Antes de comenzar, te recomiendo que prepares tu equipo para programar en Cairo ❤️ con el tutorial pasado.
? El futuro de Ethereum es hoy y ya está aquí. Vamos a aprender a usar un ecosistema:
- Sostiene a dYdX, DeFi que ya hizo cuatrocientos billones de trades y representa alrededor de un cuarto del total de las transacciones hechas en ethereum. Funcionan apenas desde hace 18 meses y constantemente vencen a Coinbase en volumen de trades. Redujeron el precio de las transacciones de 500 a 1,000 veces. Son tan baratas que no necesitan cobrar el gas a los usuarios ?.
- En la la semana del 7 al 13 de marzo de 2022, por primera vez, logró tener 33% más transacciones que Ethereum ?.
Y apenas es el comienzo. Aprende un poco más sobre el ecosistema de Starkware en este texto corto. Únete al mayor Meetup de habla hispana sobre StarkNet. Saluda en el el canal
1. Sumar dos números
Para aprender los básicos de Cairo crearemos juntos una función para sumar dos números ?. El código es muy sencillo pero nos ayudará a entender mejor muchos conceptos de Cairo. Nos basaremos fuertemente en la documentación de Cairo. La documentación es excelente al día de hoy no está lista para fungir como un tutorial estructurado para principiantes. Aquí buscamos solucionar esto ?.
Aquí está nuestra código para sumar dos números. Puedes pegarlo directamente en tu editor de código o IDE. En mi caso estoy usando VSCode con la extensión de Cairo.
No te preocupes si no entiendes en este punto todo lo que está sucediendo. Pero @espejelomar se preocupará si al final del tutorial no comprendes cada línea de este código. Avísame si es así porque mejoraremos ?. Cairo es un lenguaje low-level por lo que será más díficil que aprender Python, por ejemplo. Pero valdrá la pena ?. Ojos en la meta.
Veamos línea por línea y con ejemplos adicionales lo que estamos haciendo.
%builtins output from starkware.cairo.common.serialize import serialize_word func suma_dos_nums(num1: felt, num2: felt) -> (sum): alloc_locals local sum = num1+num2 return(sum) end func main{output_ptr: felt*}(): alloc_locals const NUM1 = 1 const NUM2 = 10 let (sum) = suma_dos_nums(num1 = NUM1, num2 = NUM2) serialize_word(sum) return () end
2. Los builtins
Al comienzo de nuestro programa en Cairo escribimos
La interacción entre
3. Importando
Cairo está contruido arriba de Python por lo que importar funciones y variables es exactamente igual. La línea
Así se importan varias funciones de una misma biblioteca:
4. Los field elements (felt)
En Cairo cuando no se específica el type de una variable o argumento se le asigna automáticamente el tipo
5. Los struct (los diccionarios de Cairo?)
Además de los
Podemos crear nuestra propia estructura, estilo diccionario de Python:
struct MiStruct: member primer_miembro : felt member segundo_miembro : felt end
Así definimos un nuevo tipo de datos llamado
Podemos crear una variable de tipo
Con
6. Las tuplas (tuples, en inglés)
Las tuplas en Cairo son prácticamente iguales a las tuplas en Python:
La documentación de Cairo es muy clara en su definición de las tuplas. Aquí su ejemplo:
# Una tupla con tres elementos local tuple0 : (felt, felt, felt) = (7, 9, 13) local tuple1 : (felt) = (5,) # (5) is not a valid tuple. # Una tupla con nombre no requiere una coma final local tuple2 : (a : felt) = (a=5) # Tupla que contiene otra tupla. local tuple3 : (felt, (felt, felt, felt), felt) = (1, tuple0, 5) local tuple4 : ((felt, (felt, felt, felt), felt), felt, felt) = ( tuple3, 2, 11) let a = tuple0[2] # let a = 13. let b = tuple4[0][1][2] # let b = 13.
7. La estructura de las funciones y comentarios
La definición de una función en Cairo tiene el siguiente formato:
func función(arg1: felt, arg2) -> (retornado): # Cuerpo de la función return(retornado) end
- Definir el scope de la función (alcance, en español). Comenzamos la función con funcy la terminamos conend. Esto define el scope de nuestra función llamadafunción.
- Argumentos y nombre. Definimos los argumentos que recibe la función entre paréntesis a un lado del nombre que definimos para nuestra función, funciónen este caso. Los argumentos pueden llevar su type (tipo, en español) definido o no. En este casoarg1debe ser de typefeltyarg2puede ser de cualquier type.
- Retornar. Necesariamente tenemos que agregar return(). Aunque la función no esté regresando algo. En este caso estamos retornando una variable llamadaretornadopor lo que colocamosreturn(retornado). Aún si no retornaramos nada tendríamos que agregarreturn().
- Comentarios. En Cairo comentamos con #. Este código no será interpretado al correr nuestro programa.
Como con otros lenguajes de programación. Necesitaremos una función
8. Interactuando con pointers (punteros, en español): parte 1
Supongamos que tenemos una variable de nombre
- var*es un pointer a la dirección en memoria del objetovar.
- [var]es el valor guardado en la direcciónvar*.
- &vares la dirección al objetovar.
- &[x]esx. Puedes ver quexes una dirección?
9. Argumentos ímplicitos
Antes de explicar cómo funcionan los argumentos ímplicitos, una regla: Si una función
Dicho esto, veamos cómo se ve una función con un argumento ímplicito. La función es serialize_word que se encuentra disponible en la biblioteca
%builtins output func serialize_word{output_ptr : felt*}(word : felt): assert [output_ptr] = value let output_ptr = output_ptr + 1 # El nuevo valor de output_ptr es implícitamente # añadido en return. return () end
Esto será un poco confuso, prepárate. Intentaré de hacer todo muy claro ?. Para que una función reciba argumentos ímplicitos colocamos entre
En el ejemplo con la función
Siguiendo la regla definida al comienzo, cualquier función que llame a
func main{output_ptr: felt*}(): alloc_locals const NUM1 = 1 const NUM2 = 10 let (sum) = sum_two_numbers(num1 = NUM1, num2 = NUM2) serialize_word(word=sum) return () end
Vemos que llamamos a
Entonces, el argumento ímplicito es ímplicito porque:
- Dentro de la función ímplicita, automáticamente se retorna el valor final del argumento ímplicito.
- Cuando se llama a la función ímplicita, no necesitamos indicar que vamos a ingresar el argumento ímplicito. Automáticamente se incluye el valor ímplicito.
10. Locals (locales, en español)
Estamos casi listos para comprender al 100 lo que hicimos en nuestra función que suma dos números. Lo sé, ha sido un camino piedroso ?. Pero hay un arcoíris al final del tutorial ?.
Así definimos una variable local:
Como ejemplo, mira esta parte de nuestra función que suma dos números:
func sum_two_numbers(num1: felt, num2: felt) -> (sum): alloc_locals local sum = num1+num2 return(sum) end
Es muy sencillo ?.
Como no queremos que sea tan fácil, hablemos de memoria. Cairo guarda la variables locales en relación al frame pointer (
11. Constants (constantes, en español)
Muy simples. Solo recuerda que deben dar un entero (un field) cuando compilemos nuestro código. Crea una constant:
const NUM1 = 1
12. References (referencias, en español)
Este es el formato para definir una:
let ref_nombre : ref_type = ref_expr
Donde
Una referencia se puede reasignar (documentación de Cairo):
let a = 7 # a está inicialmente ligada a la expresión 7. let a = 8 # a ahora está ligada a la expresión 8.
En nuestra suma de dos números creamos una referencia llamada
let (sum) = suma_dos_nums(num1 = NUM1, num2 = NUM2)
13. Conclusión
Felicidades ?. Hemos aprendido los básicos de ? Cairo. Con este conocimiento podrías identificar lo que se hace en cada línea de nuestra función que suma dos enteros ?.
En los siguientes tutoriales aprenderemos más sobre los pointers y el manejo de la memoria; la common library de cairo; cómo funciona el compilador de Cairo; y más!
Cualquier comentario o mejora por favor comentar con @espejelomar ?.