Presentación de la máquina virtual Algorand: versión AVM 0.9

La versión 2.7.1 del software representa una mejora importante para la cadena de bloques con la introducción de la Máquina virtual Algorand (AVM) que admite un lenguaje Turing completo. Además de aceptar ahora el bucle y la recursividad, también ofrece a los desarrolladores la capacidad de crear subrutinas, admite programas de mayor tamaño y muchos códigos de operación adicionales nuevos. El protocolo también se ha mejorado e incluye muchas características nuevas. En la siguiente publicación se resumirá muchas de estas y sus capacidades.

Bucles y subrutinas

AVM es compatible con el lenguaje TEAL y con esta versión, mas precisamente la 4. En versiones anteriores de TEAL, se proporcionaban códigos de operación de ramificación directa para admitir la omisión de secciones no relevantes. Con ésto, los tres códigos de operación ( b, bnz y bz) admiten la ramificación en ambas direcciones. Lo cuál permite que se realicen bucles en sus contratos inteligentes.

#pragma version 4
// loop 1 - 10
// init loop var
int 0 
loop:
int 1
+
// implement loop code
// ...
// check upper bound
int 10
<=
bnz loop

Además del bucle, el AVM también admite los dos nuevos códigos de operación (callsub y retsub) que proporcionan funcionalidad de subrutina. Cuando callsub se llama, la ubicación actual en el programa se guarda y salta inmediatamente a la etiqueta pasada al código de operación. Cuando retsub realiza una llamada al código de operación, el AVM reanuda la ejecución en el punto anterior guardado.

#pragma version 4
// jump to main loop
b main
// subroutine
my_subroutine:
// implement subroutine code
// with the two args
retsub

main:
int 1
int 5
callsub my_subroutine
return

El uso de bucles con subrutinas permite escribir contratos inteligentes más sofisticados. Por ejemplo, el siguiente utiliza un cálculo simplificado para verificar la primacía de un número.

#pragma version 4
// Simplistic primality test
// Uses this formula
// number_to_check < 2 fail
// number_to_check == 2 pass
// number_to_check % 2 == 0 fail
// for( i=3 < sqrt(number_to_check); i+=2){
//      if( number_to_check % i == 0) fail;
// }

// check if just creating app 
txn ApplicationID
bz creation
// load number_to_check
txn ApplicationArgs 0
btoi // it must be an integer
dup // make a copy
store 0 // store number_to_check
sqrt // take the square root of the number
store 1 // save the square root of the number
load 0
// number_to_check == 2 pass
int 2 
==
bnz finished
// number_to_check < 2 fail
load 0
int 2
<
bnz fail
// number_to_check % 2 == 0 fail
load 0 
int 2
%
int 0
==
bnz fail
// branch to main loop
b main
// subroutine
// if( number_to_check % i == 0) fail
// i is on top of stack
check_prime:
load 0 
swap
%
int 0
==
bnz fail
retsub
// main loop
// for( i < sqrt(number_to_check); i+=2){}
main:
int 1 // initialize i
loop:
int 2
+
dup //make a copy of i
// call subroutine for specific i
callsub check_prime
// i < sqrt(number_to_check)
dup // keep i on stack
load 1 // load sqrt of number_to_check
<=
bnz loop
// the number is a prime
return 

creation:
int 1
return
finished:
int 1
return
fail:
int 0
return

Compartir datos entre contratos

El AVM de Algorand brinda a los contratos inteligentes acceso al espacio temporal que se puede usar para almacenar valores temporalmente, mientras se ejecuta el contrato. TEAL se ha mejorado para permitir que otros contratos lean este espacio temporal. El mismo solo puede ser leído por otras transacciones con las que la transacción específica está agrupada de forma atómica. Además, debido a que las transacciones agrupadas se ejecutan en el orden en que se asocian, los contratos no pueden leer el espacio temporal para las transacciones que ocurren después del actual.

Esta acción se puede realizar utilizando uno de los dos nuevos códigos de operación ( gload y gloads). Con el gload, la transacción específica a leer y el número de ranura deben pasarse al comando. El gloads utilizará el último valor de la pila como índice de transacción y debe pasarse el número de ranura para leer.

// read the first 
// transactions 10th
// slot of scratch space
gload 0 10
// read the second
// transactions 20th
// slot of scratch space
int 1
gloads 20

Tarifas de transacción agrupadas

La tarifa de transacción mínima en Algorand es actualmente de 1000 micro Algos. Esto significa que cualquier usuario que desee enviar una transacción debe pasar esta cantidad con su envío. En algunos casos, otras dapps pueden querer cubrir el costo de las transacciones de sus clientes. Con esta versión, el protocolo ahora admite tarifas agrupadas donde una transacción puede pagar éstas, desde otras transacciones dentro de un grupo atómico. Para las transacciones atómicas, el protocolo suma el número de transacciones y calcula la cantidad total de tarifas requeridas, luego calcula la cantidad enviadas por todas las transacciones. Si las cobradas son mayores o iguales a la cantidad requerida, se cumplirá con el requisito de la tarifa de transacción.

El siguiente ejemplo ilustra la agrupación de dos transacciones, estableciendo tarifas en una para ambas transacciones.

#create two transactions (smart contract call and asset xfer)
$ goal app call --app-id [APPID] --fee 2000  --app-arg "str:check"  --from [ACCOUNT1] --out=unsginedtransaction1.tx
$ goal asset send -a 1 --fee 0 --assetid [ASSETID] -f [ACCOUNT1] -t [ACCOUNT2]  --out=unsginedtransaction2.tx
# combine and group the two transactions
$ cat unsginedtransaction1.tx unsginedtransaction2.tx  > combinedtransactions.tx
$ goal clerk group -i combinedtransactions.tx -o groupedtransactions.tx 
# Split grouped files and sign individual ones
$ goal clerk split -i groupedtransactions.tx -o split.tx 
$ goal clerk sign -i split-0.tx -o signout-0.tx
$ goal clerk sign -i split-1.tx -o signout-1.tx
# combine signed txs and send
$ cat signout-0.tx signout-1.tx > signout.tx
$ goal clerk rawsend -f signout.tx

Evaluación dinámica del costo del código de operación

Para mantener un alto rendimiento de transacciones, Algorand limita la cantidad de tiempo de procesamiento que puede usar un contrato inteligente mientras se ejecuta. Anteriormente, esto se basaba en un análisis estático del código donde cada uno tiene un costo asociado. Estos valores se totalizaron y si la cantidad utilizada era mayor que el límite, el contrato no se podía implementar.

Si usa la versión 4 de TEAL o superior, los costos del código de operación ahora se evalúan dinámicamente en lugar de estáticamente. La versión 3 (o inferior) todavía se evalúa estáticamente. Los límites actuales se establecen en 20000 para apátridas y 700 para cada aprobación.

Con las nuevas capacidades del AVM, Algorand pasó a un algoritmo de evaluación de código de operación dinámico. Debido a las subrutinas y bucles, muchas partes de un contrato inteligente no se ejecutarán en todas las llamadas. Con la evaluación dinámica de los códigos de operación realmente ejecutados, los desarrolladores pueden escribir contratos inteligentes más grandes y modulares.

Se incrementaron los límites de los contratos inteligentes con estado

Los contratos inteligentes con estado en versiones anteriores del protocolo se limitaron a 1 KB cada uno para la aprobación y los programas claros. Con esta versión, se ha combinado la duración máxima de estos dos programas. Lo que significa que tiene 2 KB para el total de ambos, de forma predeterminada. Además, puede solicitar hasta 3 ExtraProgramPages de 2 KB cada uno, lo que da como resultado un límite de 8 KB para ellos programas.

La asignación de páginas de programa adicionales aumentará el requisito de saldo mínimo para crear la aplicación.

La solicitud de páginas de programa adicionales está disponible al crear la aplicación de contrato inteligente con estado utilizando goal y los SDK.

goal app create --creator [CREATOR_ACCOUNT]  --approval-prog ./mysmartcontract.teal --global-byteslices 0 --global-ints 0 --local-byteslices 0 --local-ints 0  --clear-prog ./myclear.teal  --extra-pages 2

Cambios en la matriz de transacciones

Algo y los contratos inteligentes con estado se denominan Aplicaciones. Cuando se implementan, se hace referencia a ellos mediante un ID de aplicación. Estos se comunican mediante transacciones de aplicaciones. La transacción de la aplicación principal proporciona información adicional que se puede pasar y procesar mediante el código TEAL del contrato inteligente con estado. Por ello, se puede pasar un conjunto de matrices con la transacción, lo que indica al protocolo que cargue datos adicionales para usar en el contrato.

Estas matrices son la matriz de aplicaciones, la de cuentas, la de activos y la de argumentos

  • La matriz de aplicaciones se usa para pasar otras ID de contrato inteligente con estado, que el mismo llamado puede necesitar usar en una capacidad de búsqueda.
  • La matriz de cuentas permite que se pasen cuentas adicionales al contrato para obtener información de saldo y almacenamiento local.
  • La de activos se utiliza para pasar una lista de ID de activos que se pueden utilizar para recuperar información de configuración y saldo de activos.
  • La matriz de argumentos se utiliza para pasar argumentos estándar al contrato. Con esta versión, no se han realizado cambios en la de argumentos.

Todavía está limitado a 16 argumentos con un límite de tamaño de 2k para el total de éstos. Se han cambiado los límites de tamaño de las otras tres matrices. En versiones anteriores, la matriz de cuentas se limitaba a 4 cuentas, la de activos y la de aplicaciones se limitaban a 2 cada una. El AVM aún limita la matriz de cuentas a no más de 4, los activos y las matrices de aplicaciones combinados y totalizados con la matriz de cuentas no pueden exceder de 8. Por ejemplo, puede tener 8 aplicaciones en la matriz siempre que no pase nada en las matrices de cuentas o activos con la transacción específica.

Al acceder a cualquiera de estas matrices dentro de su código TEAL, normalmente especifica un índice en ellas. Con TEAL versión 4 y superior, también puede especificar un valor específico. Con la matriz de cuentas, puede especificar una dirección específica, con aplicaciones y activos, puede especificar la ID determinada (uint64). Tenga en cuenta que al asignar los valores concretos, aún debe verificar que la cuenta, el activo o la aplicación estén realmente en la matriz. Por ejemplo, utilizando el código de operación balance, el saldo de Algo de una cuenta se puede verificar de las siguientes formas:

int 1 // first account in the accounts array
balance
int 1000000 
> // greater than one Algo
// specify the address of an account that is in the accounts array
addr QMDK7R4W54DKR7ISCAOQSBWVEDI2NYD35VO36BVQFBZ2BR3WU3BURY35QE
balance
int 1000000 
> // greater than one Algo
&&

Almacenamiento local y global más versátil

Los contratos inteligentes con estado ALGO y tienen la capacidad de leer y escribir variables de almacenamiento a nivel mundial para el contrato y localmente para las cuentas que han optado por el contrato inteligente con estado. Actualmente, estos están limitados a 64 pares clave-valor para el estado global y 16 pares clave-valor para cada cuenta que se suscriba al mismo. Cada uno de estos pares clave-valor está limitado a 64 bytes para la clave y 64 bytes para el valor.

Para muchas aplicaciones, esta limitación no es un escenario de uso ideal. Esta limitación ahora se ha modificado para permitir que la combinación de pares clave-valor consuma 128 bytes. Esto permite a los desarrolladores crear nombres de clave más pequeños y tener más almacenamiento para el valor de la clave. La misma todavía está restringida a 64 bytes o menos.

Cambio de URL de activo

Al crear un activo estándar de Algorand (ASA), el creador puede especificar una URL de ésta. El siguiente se usa a menudo para hacer referencia a recursos fuera de la cadena, como recursos IPFS. Este campo se ha limitado a 32 bytes, lo que no es ideal para muchos eslabones fuera de la cadena. Con esta versión, el límite aumenta a 96 bytes, lo que permite una URL mucho más largas.

Identificaciones creables conocidas

El Protocolo de Algorand asigna un identificador (ID) al crear Activos estándar de Algorand (ASA) o Contratos inteligentes con estado. Estos ID se utilizan para hacer referencia al activo o al contrato más adelante, cuando se utilizan en una transacción o en una llamada al contrato inteligente con estado. Debido a que estos se asignan cuando se crea el activo o el contrato, el ID no está disponible hasta que la transacción de creación se haya ejecutado por completo.

Muchas veces en un contrato, es posible que necesite la identificación de otro, o activo que se está creando dentro de un grupo atómico de transacciones. Por ejemplo, es posible que desee almacenar la ID de éste u otra ID de contrato inteligente en el estado del contrato para su uso posterior.

Esta operación se puede realizar utilizando uno de los dos nuevos códigos de operación ( gaid y gaids). Con el gaid, la transacción específica a leer debe pasarse al comando. El gaids, utilizará el último valor de la pila como índice de transacción.

// Get the created id of the asset created in the first tx
gaid 0
// Get the created id of the asset created in the second tx
int 1
gaids

Aritmética Byteslice

Hay disponible un nuevo conjunto de códigos de operaciones que permiten ejecuciones matemáticas en segmentos de bytes. Los segmentos de bytes se interpretan como enteros sin signo de big-endian. Cada operando puede tener hasta 64 bytes, lo que puede producir un entero sin signo de 512 bits. Estos códigos de operación ( b+, b-, b*, b/, b%, b<, b>, b<=, b>=, b== y b!=) Además, el apoyo, resta, multiplicación, división, módulo, y un conjunto de códigos de operación de comparación.

// byte slice 1
byte 0x12f0
// byte slice 2
byte 0x3C
// multiply
b*
byte 0x047040
// compare byte slices
b==
assert

Además, los códigos de operación ( b\, b&, b^, b~) están disponibles para llevar a cabo bit a bit OR, AND, XOR, y las operaciones invertir. El AVM también proporciona un código de operación (bzero) para producir un segmento de bytes con cero de una longitud específica y el bitlen que devuelve el conjunto de bits de orden más alto.

byte 0xFFFE
dup
// bitwise invert
b~ 
// bitwise and
b&
// 2 byte empty byte array
int 2
bzero
b==
assert
// determine highest bit set
byte 0xFFFE
bitlen
int 16
==
assert

Códigos de operación matemáticos adicionales

El divmodw ahora está disponible para admitir números de 128 bits producidos por mulw y addw.

#pragma version 4
// Demonstrate a "function" that expects three u64s on stack,
// and calculates B*C/A. (Following opcode documentation
// convention, C is top-of-stack, B is below it, and A is
// below B.
// check if just creating app 
txn ApplicationID
bz creation
// load A
txn ApplicationArgs 0
btoi // it must be an integer
store 0 // store A
// load B
txn ApplicationArgs 1
btoi // it must be an integer
store 1 // store B
// load C
txn ApplicationArgs 2
btoi // it must be an integer
store 2 // store C
b main
muldiv:
mulw        // multiply B*C. puts TWO u64s on stack
int 0       // high word of C as a double-word
dig 3       // pull C to TOS
divmodw
pop     // pop unneeded remainder low word
pop     // pop unneeded remainder high word
swap
int 0
==
assert  // ensure high word of quotient was 0
swap    // bring C to surface
pop     // in order to get rid of it
retsub
main:
load 0
load 1
load 2
callsub muldiv
int 16
== 
return
creation:
int 1
return
finished:
int 1
return
fail:
int 0
return

El AVM también admite varios códigos de operación matemáticos nuevos, incluidos exp y expw que permiten elevar la variable A a la potencia Bth. Los siguientes para desplazar bits a la izquierda y la derecha y, el código de operación que devuelve el entero más grande que es menor o igual que el argumento al cuadrado.

Cálculo del saldo mínimo del contrato inteligente con estado

Con el aumento en el tamaño permitido de los contratos inteligentes con estado, entrará en vigencia un nuevo cálculo de saldo mínimo. La fórmula para computar este saldo mínimo se muestra a continuación:

100000 (1 + ExtraProgramPages) + (28500) esquema.NumUint + (50000) * esquema.NumByteSlice

Cualquier usuario que opte por el contrato inteligente con estado verá su saldo mínimo incrementado en la siguiente cantidad:

100000 + (28500) esquema.NumUint + (50000 esquema.NumByteSlice)

El cálculo del saldo mínimo opcional no ha cambiado en esta versión.


Este artículo ha sido escrito originalmente por Jason  Weathersby  en «Artículos» del portal para desarrolladores de Algorand  y traducido por AlgoLatam.

Original Article: https://developer.algorand.org/articles/introducing-algorand-virtual-machine-avm-09-release/

Deja una respuesta

Tu dirección de correo electrónico no será publicada.