Saltar al contenido principal

Almacenamiento

El ejemplo de incremento demuestra cómo llamar a un contrato desde otro contrato.

Abrir en Gitpod

Ejecutar el ejemplo

Primero, pasa por el proceso de Configuración para configurar tu entorno de desarrollo, luego clona la etiqueta v22.0.1 del repositorio soroban-examples:

git clone -b v22.0.1 https://github.com/stellar/soroban-examples

O, salta la configuración del entorno de desarrollo y abre este ejemplo en Gitpod.

Para ejecutar las pruebas del ejemplo, navega al directorio increment y usa cargo test.

cd increment
cargo test

Deberías ver la salida:

running 1 test
test test::test ... ok

Código

increment/src/lib.rs
const COUNTER: Symbol = symbol_short!("COUNTER");

#[contract]
pub struct IncrementContract;

#[contractimpl]
impl IncrementContract {
pub fn increment(env: Env) -> u32 {
let mut count: u32 = env.storage().instance().get(&COUNTER).unwrap_or(0);
log!(&env, "count: {}", count);

count += 1;
env.storage().instance().set(&COUNTER, &count);
env.storage().instance().extend_ttl(50, 100);

count
}
}

Ref: https://github.com/stellar/soroban-examples/tree/v22.0.1/increment

Cómo Funciona

Este contrato obtendrá un valor de contador del almacenamiento (o usará el valor 0 si no se ha almacenado ningún valor todavía), y aumentará este contador cada vez que se llame.

Abre el archivo increment/src/lib.rs o consulta el código anterior para seguir el proceso.

Clave de Datos del Contrato

Los datos del contrato están asociados a una clave, que se puede usar en un momento posterior para buscar el valor.

const COUNTER: Symbol = symbol_short!("COUNTER");

Symbol es un tipo de cadena corto (de hasta 32 caracteres de longitud) con un espacio de caracteres limitado (solo se permiten caracteres a-zA-Z0-9_). Los identificadores como los nombres de las funciones del contrato y las claves de los datos del contrato están representados por Symbols.

El macro symbol_short!() es una forma conveniente de pre-calcular símbolos cortos de hasta 9 caracteres de longitud en tiempo de compilación usando Symbol::short. Genera una constante de tiempo de compilación que adhiere al conjunto de caracteres válidos de letras (a-zA-Z), números (0-9) y guiones bajos (_). Si un símbolo excede el límite de 9 caracteres, se debería utilizar Symbol::new para crear símbolos en tiempo de ejecución.

Acceso a los Datos del Contrato

let mut count: u32 = env
.storage()
.instance()
.get(&COUNTER)
.unwrap_or(0); // If no value set, assume 0.

La función Env.storage() se utiliza para acceder y actualizar los datos del contrato. El contrato que se está ejecutando es el único que puede consultar o modificar los datos del contrato que ha almacenado. Los datos almacenados son visibles en el ledger dondequiera que el ledger sea visible, pero los contratos que se ejecutan dentro del entorno Soroban están restringidos a sus propios datos.

La función get() obtiene el valor actual asociado con la clave del contador.

Si no hay ningún valor almacenado actualmente, se devolverá el valor dado a unwrap_or(...) en su lugar.

Los valores almacenados como datos del contrato y recuperados son transmitidos desde el entorno y se expanden al tipo especificado. En este caso, un u32. Si el valor puede ser expandido, el tipo devuelto será un u32. De lo contrario, si un desarrollador hizo que fuera de algún otro tipo, ocurriría un pánico al desenrollar.

env.storage()
.instance()
.set(&COUNTER, &count);

La función set() almacena el nuevo valor de conteo asociado con la clave, reemplazando el valor existente.

Gestionar TTL de Datos del Contrato con extend_ttl()

env.storage().instance().extend_ttl(100, 100);

Todos los datos del contrato tienen un Tiempo de Vida (TTL), medido en ledgers, que debe ser extendido periódicamente. Si el TTL de una entrada no se extiende periódicamente, la entrada finalmente se convertirá en "archivada" Puedes aprender más sobre esto en el documento Archivado de Estado.

Por ahora, es bueno saber que hay tres tipos de almacenamiento: Persistent, Temporary y Instance. Este contrato solo utiliza almacenamiento Instance: env.storage().instance(). Cada vez que se incrementa el contador, el TTL de este almacenamiento se extiende por 100 ledgers, o alrededor de 500 segundos.

Pruebas

Abre el archivo increment/src/test.rs para seguir el proceso.

increment/src/test.rs
#[test]
fn test() {
let env = Env::default();
let contract_id = env.register(IncrementContract, ());
let client = IncrementContractClient::new(&env, &contract_id);

assert_eq!(client.increment(), 1);
assert_eq!(client.increment(), 2);
assert_eq!(client.increment(), 3);
}

En cualquier prueba, lo primero que siempre se requiere es un Env, que es el entorno Soroban en el que se ejecutará el contrato.

let env = Env::default();

El contrato se registra con el entorno usando el tipo de contrato.

let contract_id = env.register(IncrementContract, ());

Todas las funciones públicas dentro de un bloque impl que está anotado con el atributo #[contractimpl] tienen una función correspondiente generada en un tipo de cliente generado. El tipo de cliente se llamará igual que el tipo de contrato con Client agregado.

let client = IncrementContractClient::new(&env, &contract_id);

La prueba verifica que el resultado devuelto sea como esperamos.

assert_eq!(client.increment(), 1);
assert_eq!(client.increment(), 2);
assert_eq!(client.increment(), 3);

Construir los Contratos

Para crear el contrato en un archivo .wasm, usa el comando stellar contract build.

stellar contract build

El archivo .wasm debería encontrarse en el directorio target del contrato después de crear el contrato:

target/wasm32-unknown-unknown/release/soroban_increment_contract.wasm

Ejecutar el Contrato

Si tienes stellar-cli instalado, puedes desplegar el contrato y invocar la función del contrato.

Desplegar

stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/soroban_increment_contract.wasm \
--id a

Invocar

stellar contract invoke \
--wasm target/wasm32-unknown-unknown/release/soroban_events_contract.wasm \
--id 1 \
-- \
increment

Resultado

La siguiente salida debería ocurrir la primera vez que se use el código anterior.

1

El valor se incrementará cada vez que se invoque la función del contrato.