Almacenamiento
El ejemplo de incremento demuestra cómo llamar a un contrato desde otro contrato.
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
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.
#[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
- macOS/Linux
- Windows (PowerShell)
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/soroban_increment_contract.wasm \
--id a
stellar contract deploy `
--wasm target/wasm32-unknown-unknown/release/soroban_increment_contract.wasm `
--id a
Invocar
- macOS/Linux
- Windows (PowerShell)
stellar contract invoke \
--wasm target/wasm32-unknown-unknown/release/soroban_events_contract.wasm \
--id 1 \
-- \
increment
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.