Back to Blog

Prácticas de Seguridad en el Desarrollo con Move (1): Hola Mundo

Code Auditing
November 7, 2022
11 min read

Con el lanzamiento de la red principal de Aptos network el 18 de octubre, el lenguaje de programación Move y su ecosistema continúan expandiendo su influencia. Para involucrar a la comunidad, publicaremos una serie de artículos con prácticas de desarrollo seguro en Move. Te guiaremos hacia el mundo de Move a través de ejemplos, explicaciones y, lo más importante, prácticas de seguridad.

TL;DR

Este artículo te explicará:

  • cómo crear y desarrollar una aplicación en Aptos;
  • cómo se ve un módulo (es decir, un contrato inteligente en Move);
  • cómo compilar y publicar un módulo en tu red local;
  • cómo interactuar con el módulo y verificar el evento emitido en el navegador.

0x1. Acerca de Move y su Ecosistema

Move es una herencia de Diem (el nombre anterior era Libra antes de diciembre de 2020), diseñado para el desarrollo de contratos inteligentes. Se afirma que es seguro, rápido y flexible, con el objetivo de convertirse en el lenguaje de próxima generación. Sin embargo, los proyectos recién introducidos como Aptos y Sui no adoptan el Move original directamente, sino que se han realizado algunas modificaciones para satisfacer sus necesidades.

A menos que se indique lo contrario, nos centraremos principalmente en las prácticas de desarrollo en el contexto de Aptos, ya que las ideas son genéricas para otros proyectos basados en Move. También asumimos que ya has revisado el MoveBook para una comprensión básica del lenguaje de programación Move.

0x2. Preparar el Entorno

0x2.1 Cadena de Herramientas de Aptos

Aptos ya ha integrado Move en su CLI. Por lo tanto, se recomienda seguir la instalación de la CLI para instalar la cadena de herramientas correspondiente. Una vez completada la instalación, escribe aptos en la terminal y deberías ver la siguiente salida:

$ aptos
aptos 1.0.1
Aptos Labs <[email protected]>
Command Line Interface (CLI) for developing and interacting with the Aptos blockchain
USAGE:
    aptos <SUBCOMMAND>
OPTIONS:
    -h, --help       Print help information
    -V, --version    Print version information
SUBCOMMANDS:
    account       Tool for interacting with accounts
    config        Tool for interacting with configuration of the Aptos CLI tool
    genesis       Tool for setting up an Aptos chain Genesis transaction
    governance    Tool for on-chain governance
    help          Print this message or the help of the given subcommand(s)
    info          Show build information about the CLI
    init          Tool to initialize current directory for the aptos tool
    key           Tool for generating, inspecting, and interacting with keys
    move          Tool for Move related operations
    node          Tool for operations related to nodes
    stake         Tool for manipulating stake and stake pools

0x2.2 Red de Prueba Local y Cuenta

Aptos proporciona varias redes (es decir, mainnet, testnet, devnet y red de prueba local) para el desarrollo y la implementación. En este artículo, utilizaremos la red de prueba local.

Para iniciar la red de prueba local, escribe el siguiente comando:

$ aptos node run-local-testnet --with-faucet --force-restart

Deberías ver la salida:

......
Aptos is running, press ctrl-c to exit
Faucet is running.  Faucet endpoint: 0.0.0.0:8081

Ahora puedes crear tu cuenta escribiendo el siguiente comando (probablemente en otra ventana de terminal si deseas mantener la anterior en primer plano):

$ aptos init

Este comando te abrirá un shell interactivo que requiere especificar algunas propiedades. Aquí elegimos la red local. Después de eso, habrá una carpeta .aptos en el directorio actual con la configuración de tu cuenta predeterminada. Verifica el archivo y copia la dirección de tu account (p. ej., c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd).

Consejo#1: ¡Mantén seguro tu archivo de configuración de cuenta! ¡Tu clave privada está escrita en él!

0x3. El Primer Programa Hola Mundo

El programa Hola Mundo siempre se utiliza como primer paso para aprender a escribir código. Nos gustaría seguir esta convención para demostrar la forma de desarrollar aplicaciones Move.

0x3.1 Preparar el Paquete

Elige un directorio de tu preferencia y escribe el siguiente comando:

$ aptos move init --framework-local-dir "../../aptos-core/aptos-move/framework/aptos-framework" --name hello

Este comando creará un nuevo paquete Move en la ubicación indicada (es decir, el espacio de trabajo de desarrollo). Dado que algunas funciones de biblioteca del framework de Aptos son necesarias, se especifica el directorio local del framework de Aptos (puede que sea necesario cambiar la ruta relativa para una ubicación diferente); alternativamente, también se puede especificar la revisión o rama de git para el framework de Aptos usando --framework-git-rev.

Ahora podrás ver un archivo Move.toml en tu directorio. Este archivo no solo enumera algunas configuraciones de dependencias, sino que también describe el nombre y la versión del paquete. Además, también existe una carpeta llamada sources, que se utiliza para almacenar el código fuente de Move. Después de crear un archivo .move en el directorio sources, el espacio de trabajo está listo para usar.

[package]
name = 'hello'
version = '1.0.0'
[dependencies.AptosFramework]
local = '../../aptos-core/aptos-move/framework/aptos-framework'
[addresses]
BlockSec="c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd"

En la última línea de Move.toml, asociamos la dirección de la cuenta (recién creada) con BlockSec. Se utiliza para publicar el módulo (es decir, desplegar el contrato inteligente) en este paquete (se discutirá más adelante). Ten en cuenta que la dirección anterior es solo un marcador de posición, y DEBES reemplazarla con tu propia dirección de cuenta.

0x3.2 Preparar el Módulo

A continuación se muestra un módulo de ejemplo simple pero completo, que puede colocarse directamente en el archivo move (p. ej., hello.move). A continuación, nos gustaría revisar el código para ilustrar la diferencia entre Move y otros lenguajes de programación. Puedes omitir esta sección si ya estás bastante familiarizado con ellos.

module BlockSec::hello{
    use aptos_framework::account;
    use aptos_framework::event;
    use std::signer;
    use std::string::{String, utf8};
    struct SecEventStore has key{
        event_handle: event::EventHandle<String>,
    }
    public entry fun say_hello_script(account: &signer) acquires SecEventStore{
        say_hello(account);
    }
    public fun say_hello(account: &signer) acquires SecEventStore{
        let address_ = signer::address_of(account);
        if(!exists<SecEventStore>(address_)){
            move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
        };
        event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));
    }
}

Aquí definimos un módulo llamado hello que se publicará en la dirección BlockSec. La función de entrada de este módulo se llama say_hello_script, que invocará la función say_function. Es fácil deducir que este módulo se utiliza para emitir un evento con el mensaje "Hello World!" (en la función say_hello). Sin embargo, aún existen algunos detalles que deben explicarse claramente.

Específicamente, para usar la función event::emit_event en el espacio de nombres aptos_framework, necesitamos una estructura event::EventHandle porque la función emit_event tiene la siguiente declaración:

/// Emit an event with payload `msg` by using `handle_ref`'s key and counter.
public fun emit_event<T: drop + store>(handle_ref: &mut EventHandle<T>, msg: T)
struct EventHandle<phantom T: drop + store> has store {
    /// Total number of events emitted to this event stream.
    counter: u64,
    /// A globally unique ID for this event stream.
    guid: GUID,
}

Observa que EventHandle no tiene la capacidad key, lo que significa que debemos almacenarlo en otra estructura. Por lo tanto, definimos una estructura llamada SecEventStore para almacenar EventHandle:

struct SecEventStore has key{
    event_handle: event::EventHandle<String>,
}

Consejo#2: Debemos considerar las capacidades de una estructura en Move. Recuerda que solo la capacidad **_key_** puede usarse con **_move_to_**. Si un módulo devuelve una estructura que solo tiene la capacidad **_store_** y deseas preservarla en el almacenamiento global, considera definir una nueva estructura como contenedor.

Por simplicidad, usamos String para representar el mensaje. Entonces el paso final de la función say_hello es:

event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));

Consejo#3: Move no admite el tipo **_String_** de forma nativa. La biblioteca estándar proporciona la capacidad de transmitir un vector de bytes a un **_String_**. Consulta el código fuente en su repositorio de GitHub para más detalles.

Para garantizar que cada nuevo usuario deba registrarse con un SecEventStore, primero debemos verificar la existencia de la estructura en la cuenta del usuario a través de la función exists. Si el usuario no tiene el recurso, la función creará uno y lo moverá a la cuenta del usuario.

if(!exists<SecEventStore>(address_)){
    move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
};

0x3.3 Compilar y Publicar el Módulo

Cuando el módulo está listo, podemos compilarlo con el siguiente comando:

$ aptos move compile
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
{
  "Result": [
    "c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd::hello"
  ]
}

También podemos probarlo si es necesario:

$ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
Running Move unit tests
Test result: OK. Total tests: 0; passed: 0; failed: 0
{
  "Result": "Success"
}

Ahora podemos desplegar el módulo en la red de Aptos. Recuerda que hemos asociado la cuenta con BlockSec, porque un usuario solo puede publicar módulos en cuentas bajo su control. Además, el faucet ya ha financiado la cuenta con algunos APTs para pagar las tarifas de gas. Lo único que queda es publicar el módulo del paquete Move en la red de Aptos, de la siguiente manera:

$ aptos move publish --package-dir ./ --profile default
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
package size 1271 bytes
Do you want to submit a transaction for a range of [672200 - 1008300] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
  "Result":
  ...
}

Nuevamente, también es un shell interactivo, y el contenido de Result se omite.

0x3.4 Interactuar con el Módulo

Para que el módulo emita el evento, simplemente escribe el siguiente comando:

$ aptos move run --function-id default::hello::say_hello_script
Do you want to submit a transaction for a range of [34500 - 51700] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
  "Result": {
    "transaction_hash": "0x9af16532de5e79803c823fe28e3251703927d93809274b76972d8e83c6fcd433",
    ...
    }
}

Como función de entrada, la función say_hello_script puede invocarse directamente. También puedes escribir un script e invocar la función say_hello en tu script.

Consejo#4: Para una mejor experiencia de interacción, definir algunas funciones de entrada es una buena práctica. También puedes desarrollar algunos scripts para que los usuarios interactúen con tu proyecto.

A diferencia del programa Hola Mundo tradicional de Web2, el evento emitido no se mostrará en el shell. Consulta el explorador de Aptos y selecciona la red local.

Luego copia el valor de transaction_hash del shell y pégalo en la barra de búsqueda, y verás los detalles de la transacción.

Finalmente, haz clic en Events, y la red de Aptos te expresará sus saludos.

0x4. ¿Qué Sigue?

El programa Hola Mundo es solo un pequeño paso para el desarrollo de aplicaciones Move. En la próxima serie de artículos, introduciremos más sobre el desarrollo de aplicaciones Move seguras y confiables en Aptos. ¡Mantente atento!

Acerca de BlockSec

BlockSec es una empresa pionera en seguridad blockchain establecida en 2021 por un grupo de expertos en seguridad de renombre mundial. La empresa está comprometida con mejorar la seguridad y la usabilidad del emergente mundo Web3 para facilitar su adopción masiva. Con este fin, BlockSec ofrece servicios de auditoría de seguridad de contratos inteligentes y cadenas EVM, la plataforma Phalcon para el desarrollo de seguridad y el bloqueo proactivo de amenazas, la plataforma MetaSleuth para el rastreo e investigación de fondos, y la extensión MetaSuites para que los desarrolladores de web3 naveguen de manera eficiente en el mundo cripto.

Hasta la fecha, la empresa ha atendido a más de 300 distinguidos clientes como MetaMask, Uniswap Foundation, Compound, Forta y PancakeSwap, y ha recibido decenas de millones de dólares en dos rondas de financiación de prominentes inversores, incluyendo Matrix Partners, Vitalbridge Capital y Fenbushi Capital.

Sitio web oficial: https://blocksec.com/

Cuenta oficial de Twitter: https://twitter.com/BlockSecTeam

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit