Emisión de diplomas universitarios en la blockchain de Algorand

Este tutorial proporciona una aplicación práctica del uso de PyTeal para generar contratos inteligentes. Conecta a los estudiantes con el registrador de diplomas. Esta DApp demuestra cómo la cadena de bloques Algorand puede facilitar la emisión de diplomas para graduados universitarios. Los alumnos que egresen pueden optar por participar en esta DApp, y luego, una cuenta de registrador privilegiada puede emitir certificaciones específicas a estudiantes determinados. Ellos obtienen su diploma registrado en su cuenta que cualquier tercero puede auditar y verificar.

Además, el registrador puede realizar otras operaciones para la posteridad. Una de ellas es transferir las obligaciones a otra cuenta. Después de dicha transferencia, la cuenta designada se convertirá en el nuevo registrador y el antiguo perderá todos los privilegios. Éste también puede revocar los diplomas si es necesario y también eliminar la DApp completa.

Puede encontrar una descripción detallada de todas las operaciones posibles tanto para los estudiantes como para el registrador ejecutando:  python3 run_diploma.py help

Requisitos

  • Python 3

Fondo

Este tutorial sigue el repositorio de ALGO-Diploma en GitHub. Éste explica el código bloque por bloque. Consulte el repositorio para ver el proyecto completo.

 Advertencia

«Esta solución está destinada únicamente con fines de aprendizaje. No cubre la verificación de errores ni otros casos extremos. Los contratos inteligentes de esta solución NO han sido auditados. Por lo tanto, no debe usarse como una aplicación de producción.«

Configuración

Enumere las cuentas de prueba en el archivo config.yml. Por ejemplo:

registrar: "alice"

alice:
        mnemonic: "<MNEMONIC HERE>"

bob:
        mnemonic: "<MNEMONIC HERE>"

charlie:
        mnemonic: "<MNEMONIC HERE>"

APP_ID: -1

Este archivo de configuración de ejemplo enumera tres usuarios, de los cuales Alice es el registrador. El papel de éste es emitir diplomas a los estudiantes, en este caso, Bob y Charlie.

En un sistema de producción, el archivo de configuración sería reemplazado por un sistema de gestión de claves para el monedero adecuado. Consulte Algosigner, myAlgo o la cartera oficial de Algorand.

Uso del repositorio

El repositorio enumerado anteriormente está listo para usarse de la siguiente manera:

  1. Instale los paquetes de Python necesarios:pip3 install -r requirements.txt
  1. Haga el código de contrato PyTEAL: make
  1. Implementar el contrato inteligente: python3 run_diploma.py deploy

Este comando imprimirá un número de identificación para APP_ID. Asegúrese de registrar esto en el config.yml.

  1. Utilice la DApp:
  • Acepta bob el contrato inteligente: python3 run_diploma.py opt-in bob
  • Emitir un diploma a bob: python3 run_diploma.py issue-diploma bob «MIT,2020,BSc,Computer Science and Engineering»
  • Transferir las funciones del registrador a charlie: python3 run_diploma.py reassign-registrar charlie
  • Para más comandos, ejecute: python3 run_diploma.py help

Pasos

  1. Funciones
  1. Código de contrato inteligente
  1. Programa de interfaz DApp
  1. Conclusión

1. Funciones

  • Registrador: el administrador de la DApp. El registrador puede emitir y revocar diplomas. También tienen el poder de actualizar y eliminar la DApp de la cadena de bloques.
  • Estudiante: Una cuenta regular en esta DApp. Pueden recibir un diploma del registrador. Deben optar por recibir un diploma y tener la opción de dejar la DApp a voluntad.

2. Código de contrato inteligente

Esta DApp se expresa como un contrato inteligente de Algorand con estado. Está escrito en PyTEAL siguiendo las pautas de desarrollo sugeridas. El código fuente del contrato inteligente está disponible aquí.

Almacenamiento

Hay un campo de bytes globales y otros locales (por cuenta elegida). El global contiene la dirección del registrador actual. La cuenta con esta dirección tiene todos los privilegios de registro de esta DApp. El local por cuenta es donde se registra un diploma emitido. El certificado se representa como una matriz de bytes de metadatos comunes, como institución emisora, año, título y tipo de grado, etc.

Este esquema de almacenamiento se especifica de la siguiente manera durante la implementación del contrato inteligente.

# Declare application state storage (immutable)
local_ints = 0
local_bytes = 1
global_ints = 0
global_bytes = 1
global_schema = transaction.StateSchema(global_ints, global_bytes)
local_schema = transaction.StateSchema(local_ints, local_bytes)

Arquitectura general de la DApp

En esta DApp, hay una cuenta designada como registrador y todas las demás cuentas son simplemente de estudiantes. Una variable de almacenamiento global denominada «registrar» expresa qué cuenta es el registrador. Una variable de almacenamiento local en cada cuenta guarda los metadatos de cualquier diploma emitido. Las cuentas deben optar por participar en este DApp para recibir un diploma si se les otorga uno.

Esta DApp implementa una serie de comandos. Éste es una secuencia de operaciones de PyTEAL que se llaman en función de alguna lógica de flujo de control condicional dependiendo de un argumento de cadena pasado. Cada comando tiene sus respectivas comprobaciones, como la de si el llamante es el registrador cuando es necesario o el numero de argumentos suministrados.

Esta DApp admite tres comandos, emisión de diploma, revocación de éstos y reasignación de registradores. La emisión del certificado se gestiona escribiendo los metadatos del éste en el almacenamiento local de la cuenta. La revocaciones se manejan borrando el espacio asignado local de la cuenta. Por último, la reasignación del registrador se maneja sobrescribiendo la variable «registrar» de almacenamiento global con la dirección de la cuenta del nuevo.

Ayudantes contractuales

var_registrar = Bytes("registrar")
is_registrar = Txn.sender() == App.globalGet(var_registrar)

El código auxiliar simplifica el del contrato inteligente que se repite con frecuencia. La primera línea asigna el nombre de la variable del registrador global a una variable de Python para facilitar el acceso más adelante. La segunda línea verifica si el remitente de la transacción actual que invoca este contrato inteligente es el registrador actual. El resultado también se guarda en una variable de Python para cada acceso más adelante.

Lógica contractual

program = Cond(
        [Txn.application_id() == Int(0), init_contract],
        [Txn.on_completion() == OnComplete.DeleteApplication, Return(is_registrar)],
        [Txn.on_completion() == OnComplete.UpdateApplication, Return(is_registrar)],
        [Txn.on_completion() == OnComplete.OptIn, Return(Int(1))],
        [Txn.on_completion() == OnComplete.CloseOut, Return(Int(1))],
        [Txn.application_args[0] == Bytes("issue_diploma"), issue_diploma],
        [Txn.application_args[0] == Bytes("revoke_diploma"), revoke_diploma],
        [Txn.application_args[0] == Bytes("reassign_registrar"), reassign_registrar]
)

Esta es la lógica del contrato que dirige cómo reacciona la DApp a ciertos comandos. El siguiente desglose explica ésta línea por línea.

  • Txn.application_id() == Int(0): Cuando se implementa inicialmente un contrato inteligente, Txn.application_id() será 0. Este es el momento de llamar init_contract para registrar al creador como el registrador inicial de la DApp.
  • Txn.on_completion() == OnComplete.DeleteApplication: Solo permite que el registrador actual elimine esta DApp.
  • Txn.on_completion() == OnComplete.UpdateApplication: Solo permite que el registrador actual actualice esta DApp.
  • Txn.on_completion() == OnComplete.OptIn: Permita que cualquier cuenta se inscriba en esta DApp.
  • Txn.on_completion() == OnComplete.CloseOut: Permitir que cualquier cuenta salga de esta DApp
  • Txn.application_args[0] == Bytes("issue_diploma"): Ejecute la issue_diploma lógica de esta DApp
  • Txn.application_args[0] == Bytes("revoke_diploma"): Ejecute la revoke_diploma lógica de esta DApp.
  • Txn.application_args[0] == Bytes("reassign_registrar"): Ejecute la reassign_registrarlógica de esta DApp.

Inicialización de contrato

init_contract = Seq([
        App.globalPut(var_registrar, Txn.sender()),
        Return(Int(1))
])

El bloque emite un diploma a una cuenta. Éste es invocado por el comando "issue_diploma" de esta DApp. Se necesita un argumento adicional diploma_metadata = Txn.application_args[1] y una cuenta, que es la destinada para recibir los metadatos del diploma. El cuerpo del bloque realiza algunas comprobaciones de cordura, que la persona que llama es el registrador y que se pasan precisamente dos argumentos. Si esos cheques pasan, la cuenta en el índice 1, la que pasó, recibirá los metadatos del diploma.

Revocar Diploma

iploma_metadata = Txn.application_args[1]
issue_diploma = Seq([
        Assert(is_registrar),
        Assert(Txn.application_args.length() == Int(2)),
        App.localPut(Int(1), Bytes("diploma"), diploma_metadata),
        Return(Int(1))
])

Este bloqueo revoca el diploma de una cuenta. El código es invocado por el comando "revoke_diploma" de esta DApp. No se necesitan argumentos adicionales, solo una cuenta Int(1), que es la que obtendrá su diploma revocado. Como arriba, el cuerpo de este bloque realiza las mismas verificaciones, que la persona que llama es el registrador y que solo se pasa un argumento. Si se aprueban estos controles, la cuenta en el índice 1 perderá sus metadatos de diploma.

Reasignación de registrador

revoke_diploma = Seq([
        Assert(is_registrar),
        Assert(Txn.application_args.length() == Int(1)),
        App.localDel(Int(1), Bytes("diploma")),
        Return(Int(1))
])

Este bloque reasigna el registrador de esta DApp. El código es invocado por el comando "reassign_registrar" de esta DApp. No se necesitan argumentos adicionales, solo una cuenta Txn.accounts[1] la cual se convertirá en el nuevo registrador. Este bloque realiza algunas comprobaciones de coherencia antes de reasignar al registrador.

Programa al retornar instrucciones

Esta DApp no ​​requiere ningún mantenimiento particular. Por lo tanto, el programa siempre regresa correctamente.

#pragma version 3
int 1

3. Programa de interfaz DApp

Esta DApp está interconectada con un programa Python usando el SDK de Algorand. El programa se utiliza para implementar DApp, así como para invocar los diversos comandos. Gran parte del código del SDK y las funciones auxiliares se toman prestados de una aplicación de ejemplo de Algorand SDK la cual puede encontrar aquí.

Esta SDK tiene una serie de funciones. El mensaje de ayuda ejecutándose mediante: python3 run_diploma.py help,  enumera las funciones disponibles:

Available commands:
        deploy: Deploy this smart contract for the first time
        update: Update this smart contract with new TEAL code
        opt-in <account-name>: Opt-in an account into this smart contract
        close-out <account-name>: Close-out an account from this smart contract
        delete <creator-name>: Delete this smart contract
        clear <account-name>: Clear this smart contract
        issue-diploma <account-name> <diploma-metadata>: Issue a degree to an account
        revoke-diploma <account-name>: Nullify the diploma of an account
        inspect <account-name>: Inspect an account's diploma on the Algorand blockchain
        inspect-global <creator-name>: Inspect this smart contract's global state
        reassign-registrar <account-name>: Assign an account to be the current registrar
        help: Print this help message

Todos los argumentos tomados por cada función se enumeran entre paréntesis angulares <…>.

Mantenimiento de DApp

Las funciones deploy, update, delete, y clear son utilizadas por un administrador de la DAPP para su mantenimiento.

Desplegar

La implementación de un contrato inteligente comienza con la compilación de los programas TEAL en un binario codificado en base64 (el código del contrato PyTEAL se convierte en TEAL al ejecutarlo por medio de: make).

# Read the smart contract source files
smart_contract_file = open("./assets/diploma_smart_contract.teal", "rb")
smart_contract_source = smart_contract_file.read()
smart_contract_program = common.compile_program(algod_client, smart_contract_source)

clear_program_file = open("./assets/clear_program.teal", "rb")
clear_program_source = clear_program_file.read()
clear_program = common.compile_program(algod_client, clear_program_source)

Luego, se envía una transacción a la red que indica el despliegue de un nuevo contrato inteligente. El creador de esta DApp es la cuenta que envía esta transacción. En este caso, el registrador en el momento de la implementación es el creador de ésta. La formulación de esta transacción la maneja el SDK de Python.

txn = transaction.ApplicationCreateTxn(
        sender, params, on_complete, \
        smart_contract_program, clear_program, \
        global_schema, local_schema)

global_schemae  local_schema indica las variables de almacenamiento global y local, que este contrato va a utilizar.

Actualizar

La actualización del código fuente de esta DApp comienza con la compilación de los programas TEAL, de manera similar a la implementación. Sin embargo, el evento de mejora implica un tipo diferente de transacción. En particular, se debe la instrucción para indicar qué DApp actualizar. Solo el registrador actual puede actualizar ésta. El SDK de Python crea la transacción para actualizar un contrato inteligente de la siguiente manera:

txn = transaction.ApplicationUpdateTxn(sender, params, app_id, \
                                        smart_contract_program, clear_program)

Borrar

La eliminación de DApp se realiza mediante el envío de una transacción específica con el coomando app_id. Solo el registrador actual puede eliminarla. Esto se maneja de forma concisa con el SDK de Python.

txn = transaction.ApplicationDeleteTxn(sender, params, app_id)

Participación

Cualquier cuenta puede eliminar su participación de la DApp. Esto se hace enviando una transacción de compensación a la red. Esto ejecuta implícitamente clear_program de ésta para realizar cualquier limpieza residual e independientemente de si tiene éxito o no, el usuario será eliminado. El SDK de Python crea la transacción clara de la siguiente manera:

txn = transaction.ApplicationClearStateTxn(sender, params, app_id)

Uso común de DApp

Las funciones opt-in, close-out, issue-diploma, revoke-diploma, y reassign-registrar son las más comunes a ser llamadas por cualquier usuario de este DAPP.

Optar Por Modos De Almacenamiento

Dado que esta DApp utiliza almacenamiento local, cualquier cuenta que desee participar para recibir un diploma debe suscribirse. Esto se realiza mediante el envío de una transacción app_id de suscripción específica para unirse. El SDK de Python crea la transacción de suscripción de la siguiente manera:

txn = transaction.ApplicationOptInTxn(sender, params, app_id)

Cerrar

Independientemente de la función de borrado, una cuenta puede dejar una DApp cerrándola. Una cuenta la deja, solo si una transacción de cierre con el correspondiente ID se realiza correctamente, a diferencia de la función de compensación que elimina incondicionalmente una cuenta. En el caso de esta DApp, el cierre siempre se realiza correctamente. El SDK de Python crea la transacción de cierre de la siguiente manera:

txn = transaction.ApplicationCloseOutTxn(sender, params, app_id)

Emitir Diploma

El registrador emite un diploma al realizar una llamada al contrato inteligente de esta DApp. Una llamada a DApp es simplemente una transacción con los argumentos apropiados requeridos por la llamada. En el caso de la emisión del diploma, esa es la cuenta receptora del diploma, así como los metadatos del diploma: tipo de título, institución, año, etc. El SDK de Python lo facilita como una convocatoria de solicitud NoOp de la siguiente manera:

txn = transaction.ApplicationNoOpTxn(sender, params, index, app_args, accounts)

El primer argumento app_args es la cadena "issue-diploma", que designa esta convocatoria para emitir un diploma.

Revocar Diploma

Similar a la emisión del diploma, el registrador llama a la DApp enviando una transacción con los argumentos apropiados. En este caso, esta es solo la cuenta a la que se le revocará el diploma. Esto se ve facilitado por la misma llamada al SDK de Python que la anterior, pero donde el primer argumento app_args es la cadena "revoke-diploma".

Reasignar Registrador

De manera similar a las otras llamadas, la reasignación de registrador es una llamada a la DApp por parte del registrador actual. Se transmite la cuenta del futuro registrador. La llamada al SDK de Python es la misma que la anterior, pero el primer argumento app_args es la cadena "reassign-registrar".

Inspección de DApp

Las funciones inspecty inspect-global permiten que un tercero vea las variables de estado de esta DApp. Estas funciones son más útiles para determinar la integridad y validez del diploma de un estudiante, por ejemplo.

Inspeccionar

Cualquier tercero con acceso a la cadena de bloques de Algorand puede inspeccionar el almacenamiento local de una cuenta para ver su diploma. El objeto account a inspeccionar se pasa como un argumento al programa de interfaz DApp. Las variables Bytes de almacenamiento local están codificadas en base 64, por lo que la inspección decodifica el valor para que sea legible por humanos. Una función auxiliar  read_local_state,  adoptada de una aplicación de ejemplo de Algorand SDK cumple esta función.

common.read_local_state(algod_client, pub_keys[account], app_id)

Inspeccionar Global

Un tercero también puede inspeccionar la variable de almacenamiento global para ver el registrador actual. Las variables globales se almacenan en la cuenta que implementó la DApp. El programa de interfaz de ésta utiliza el registrador durante la implementación como la cuenta de creador. Sin embargo, incluso después de la reasignación del registrador, la cuenta del creador original debe pasarse para inspeccionar la variable del registrador actual global. Una función auxiliar de una aplicación de ejemplo del SDK de Algorand sirve para esta función.

common.read_global_state(algod_client, pub_keys[creator], app_id)

4. Conclusión

Esta DApp ejemplifica un caso de uso simple pero tangible para la cadena de bloques Algorand. El código está disponible abiertamente en el repositorio de ALGO-Diploma en GitHub. Esta solicitud de diploma no es complicada, pero cubre muchos conceptos fundamentales para la programación de contratos inteligentes de Algorand. Los conceptos clave explorados incluyen:

  • Redacción de un contrato inteligente PyTEAL que se adhiera a todas las mejores prácticas estándar
    • Admite el ciclo de vida completo de un contrato inteligente, desde la implementación hasta la eliminación
    • Múltiples tipos de cuentas con diferentes niveles de privilegios.
    • Comprobación de permisos para garantizar la seguridad e integridad de la aplicación.
    • Admite múltiples comandos con diferentes comportamientos.
  • Escribir un programa de interfaz usando un SDK de Algorand
    • Una interfaz fácil para desarrollar, mantener y usar la DApp.

Este código se puede utilizar de forma gratuita según se indica en la licencia MIT.


Este artículo ha sido escrito originalmente por Damian Barabonkoy en  «Tutoriales» del portal para desarrolladores de Algorand y traducido por AlgoLatam.

Original Article: https://developer.algorand.org/tutorials/issueing-university-diplomas-on-the-algorand-blockchain/

Deja una respuesta

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