mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
spanish translation smart contract dev
Signed-off-by: munapower <mmunaro@hotmail.com>
This commit is contained in:
parent
9ee0aac2ae
commit
5870033fcb
6 changed files with 651 additions and 5 deletions
|
|
@ -79,11 +79,11 @@ We'll create a digital representation of these cards on the blockchain ledger. T
|
|||
|
||||
## Smart Contract Development
|
||||
|
||||
- [Introduction](./docs/SmartContractDev/00-Introduction.md)
|
||||
- **Exercise**: [Getting Started with a Smart Contract](./docs/SmartContractDev/01-Exercise-Getting-Started.md)
|
||||
- **Exercise**: [Adding a new transaction function](./docs/SmartContractDev/02-Exercise-Adding-tx-function.md)
|
||||
- [Introduction](./docs/SmartContractDev/00-Introduction.md) [Español](./docs/SmartContractDev/00-Introduction-ES.md)
|
||||
- **Exercise**: [Getting Started with a Smart Contract](./docs/SmartContractDev/01-Exercise-Getting-Started.md) [Español](./docs/SmartContractDev/01-Exercise-Getting-Started-ES.md)
|
||||
- **Exercise**: [Adding a new transaction function](./docs/SmartContractDev/02-Exercise-Adding-tx-function.md) [Español](./docs/SmartContractDev/02-Exercise-Adding-tx-function-ES.md)
|
||||
- Reference:
|
||||
- [Detailed Test and Debug](./docs/SmartContractDev/03-Test-And-Debug-Reference.md)
|
||||
- [Detailed Test and Debug](./docs/SmartContractDev/03-Test-And-Debug-Reference.md) [Español](./docs/SmartContractDev/03-Test-And-Debug-Reference-ES.md)
|
||||
|
||||
## Client Application Development
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
# Desarrollo de Contratos Inteligentes
|
||||
|
||||
En esta sección introduciremos el concepto de Contrato Inteligente, y como la plataforma de Hyperledger Fabric maneja estos contratos. Hablaremos sobre algunos de los aspectos importantes a tener en cuenta; estos pueden ser distintos de los que aplica para otro tipo de desarrollo.
|
||||
|
||||
Este ejemplo muestra como los detalles de un activo pueden ser almacenados en el ledger mismo, con el Contrato Inteligente controlando el ciclo de vida del activo. Provee funciones transaccionales para:
|
||||
|
||||
- Crear un activo
|
||||
- Recuperar (uno o todos) los activos
|
||||
- Actualizar un activo
|
||||
- Borrar un activo
|
||||
- Transferir propiedad del activo entre partes.
|
||||
|
||||
Este tópico aborda consideraciones de diseño comunes para los contratos inteligentes. Si quieres ir directamente al código del workshop, puedes ir directamente a [comenzar](./01-Exercise-Getting-Started-ES.md) y regresar a esta página posteriormente como referencia.
|
||||
|
||||
Por favor recuerda que Hyperledger Fabric es un Blockchain Ledger y no una Base de Datos!
|
||||
|
||||
[SIG - Comenzar con un Contrato Inteligente](./01-Exercise-Getting-Started-ES.md)
|
||||
|
||||
---
|
||||
## Diseñar los activos y contratos
|
||||
|
||||
La primera y quizás la decision mas importante es - "¿qué información necesita estar bajo el control del
|
||||
ledger?". Esto es importante por varias razones.
|
||||
|
||||
- El ledger es el estado compartido entre organizaciones, ¿aplica que todas las organizaciones puedan ver la información que esta siendo compartida? Ten en cuenta que las colecciones privadas de data de Fabric pueden ser usadas cuando un subconjunto de la data del ledger tiene que permanecer privada entre partes.
|
||||
- Para cualquier actualización en el estado del ledger, ¿qué organizaciones deben ejecutar el contrato inteligente y 'endosar' los resultados antes para que el cambio sea considerado una transacción válida? ¿La política de endoso será fija, o basada en la data? Por ejemplo, puedes desear que la organización del propietario actual la endose, junto con la organización del regulador. Esto puede ser logrado con las capacidades de endoso basadas en estado.
|
||||
- ¿Cuán grande es el tamaño de la data? Es mejor cuanto mas chica sea. Recuerda que esta data tiene que ser transferida entre muchas partes y la historia de las transacciones es mantenida en el ledger. ¿Funcionaría mejor un hash seguro salado de un documento escaneado a guardar el documento completo?
|
||||
- Aunque es posible realizar consultas del estado con JSON enriquecido cuando se usa CouchDB como base de datos del estado, el peer y el ledger están optimizados para procesamiento transaccional mas que consultas. ¿Pueden las consultas ser realizadas fuera del ledger, y los resultados 'validados' mediante un contrato inteligente?
|
||||
|
||||
Para cualquier tutorial de punta-a-punta existe una contrapartida entre hacer el escenario realístico, pero no suficientemente complicado. Para este tutorial definiremos la data a ser almacenada en el ledger como un activo de un único 'objeto' con los siguientes campos. Esto se ha mantenido bastante simple, pero el enfoque debería ser familiar.
|
||||
|
||||
- ID: cadena de caracteres identificador unívoco
|
||||
- Color: cadena de caracteres representando un color
|
||||
- Size: valor numérico representando un tamaño
|
||||
- Owner: cadena de caracteres representando la identidad del propietario del activo (id de la organización mas el nombre común (CN) del certificado del cliente)
|
||||
- Appraised Value: valor numérico
|
||||
|
||||
Probablemente no todos estos valores requieran estar en el ledger, la data podría estar almacenada en un 'oráculo' fuera del ledger que proveerá un hash de la data a ser guardada en el ledger de blockchain.
|
||||
|
||||
### Claves y Consultas
|
||||
|
||||
Piensa en la base de datos de estados del ledger como un repositorio de clave-valor para persistir los activos, o más genéricamente, cualquier registro de data que quieras mantener en el ledger.
|
||||
|
||||
Es importante tener cuidado al elegir la 'clave' que será usada. Podrías usar claves simples tales como una clave lógica pasada desde un sistema externo, una UUID, o incluso usar la txid de la transacción que creo el activo. Las claves compuestas son también posibles. Éstas son construidas para formar una estructura jerárquica y permitir otros tipos de consultas basadas en claves.
|
||||
|
||||
Una cadena de caracteres para la clave puede ser armada desde una lista de cadena de caracteres separados por el byte nulo `u+0000`. Debe haber al menos una cadena en la lista. Si solo hay una cadena, esto es referido como una clave 'simple', caso contrario, es una clave 'compuesta'. Por ejemplo puedes desear crear una clave compuesta basada en el 'tipo' de activo y el ID. Las APIs de contratos inteligentes te ayudan a crear fácilmente estas claves compuestas.
|
||||
|
||||
Para claves simples, puedes hacer consultas con la misma utilizando la API `getState(key: string)`.
|
||||
|
||||
Puedes consultar también por un rango de claves usando la API `getStateByRange(startKey: string, endKey: string)`. Las consultas por rangos te permiten especificar una clave de comienzo y una de fin, y regresa un iterador de todos los clave-valor que se encontraban entre esos puntos de comienzo y fin (incluidos estos). Las claves estarán ordenadas alfanuméricamente.
|
||||
|
||||
Las claves compuestas proveen un mecanismo de consulta interesante ya que ofrecen una consulta de rango por clave parcial. Por ejemplo, si una clave compuesta tiene las cadenas `fruit:pineapples:supplier_fred:consignment_xx` (usamos aquí un colon para que sea fácil de leer ya que el byte nulo no lo es) entonces es posible emitir consultas con una clave puntera parcial.
|
||||
Por ejemplo, para consultar por todos los registros de ananás que tiene `supplier_fred` podrías hacer la consulta utilizando la clave parcial `fruit:pineapples:supplier_fred`.
|
||||
|
||||
Una manera de ver esto es visualizando las claves como si formasen una jerarquía.
|
||||
|
||||
Ten en cuenta que las claves 'simple' y 'compuesta' son almacenadas de manera distinta entre ellas. Consecuentemente una consulta por una clave simple no regresará nada que esté guardado bajo una clave compuesta, a la inversa, una consulta por una clave compuesta no regresa nada que esté guardado bajo una clave simple.
|
||||
|
||||
Los tipos de consultas mencionadas anteriormente están soportadas en ambas bases de datos de estado, tanto LevelDB como CouchDB, y consultan las 'claves' del repositorio clave-valor.
|
||||
|
||||
|
||||
Si utilizas CouchDB, puedes también consultar por el 'valor' del par clave-valor utilizando una consulta JSON enriquecida. Esto requiere que el valor se encuentre en formato JSON (como en este tutorial). Los indices en CouchDB pueden ser provistos en el paquete del contrato inteligente para hacer que las consultas JSON sean eficientes (y esto es altamente recomendado). Aún así ten presente que las consultas basadas en 'valores' nunca serán tan eficientes como las basadas en 'clave'.
|
||||
|
||||
## Funciones Transaccionales
|
||||
|
||||
Veamos cuales son los diferentes tipos de funciones transaccionales que pueden ser escritos en el Contrato Inteligente. Cada uno de estos puede ser invocado desde la aplicación cliente.
|
||||
- Funciones de tipo 'Evaluate' son invocadas de manera solo-lectura para consultar el estado en la base de datos del ledger en un peer específico.
|
||||
- Funciones de tipo 'Submit' son invocadas para enviar una transacción a todos los peers a los que se require que endosen los cambios al ledger, resultando en una operación de escritura o una operación de lectura-escritura que es enviada al servicio de ordenamiento y finalmente ejecutada en todos los peers.
|
||||
|
||||
### Aspectos Generales
|
||||
|
||||
Cada función transaccional del contrato inteligente tiene que ser marcada como tal (utilizando convenciones específicas al lenguaje). Puedes también especificar si la función esta pensada para ser 'enviada' o 'evaluada'. Esto no es obligatorio pero es una indicación para el usuario.
|
||||
|
||||
Cada función deberá considerar cómo manipulará la data para ordenarla al formato requerido para el ledger.
|
||||
|
||||
Cada función debe asegurarse que cada estado inicial es el correcto. Por ejemplo, antes de transferir un activo de Alice a Bob, debe asegurar que Alice es la propietaria, y que Alice es la identidad que esta enviando la transacción de transferencia.
|
||||
|
||||
### Funciones de Creación
|
||||
|
||||
Considera en la función de creación si quieres pasar individualmente cada elemento de data o un objeto completamente formado. Esto es mas una cuestión de preferencia personal, sin embargo, recuerda que cualquier identificador unívoco debe ser creado por fuera del contrato inteligente. La transacción será ejecutada en múltiples peers y los resultados deben coincidir por lo que no pueden ser usados cualquier función de elección aleatoria u otros procesos no determinísticos.
|
||||
|
||||
Con frecuencia hay elementos extras de data (tales como la organización que envía) que deben ser agregados.
|
||||
|
||||
### Recuperar
|
||||
|
||||
Es una buena idea pensar de antemano en los tipos de operaciones de recuperación o consulta que harán falta. ¿Puede la estructura de la clave ser creada para permitir consultas por rangos?
|
||||
|
||||
Si son requeridas consultas con JSON enriquecido, procura hacerlas lo más simple posible e incluye índices. Asegúrate además que si deseas hacer una consulta con JSON enriquecido que involucra la misma data como la 'clave' que este incluído en la estructura JSON como parte del 'valor'.
|
||||
|
||||
Existe un ejemplo de consultas de tipo obtener-todo en este workshop. Por favor considera que con el paso del tiempo esto podría recibir una gran cantidad de data que conlleva un costo en performance, ¡por lo cual generalmente no es recomendado!
|
||||
|
||||
Para consultas avanzadas, considera crear un data store aguas abajo optimizado para el tipo de consultas que necesitas. El [ejemplo de data off-chain](https://github.com/hyperledger/fabric-samples/tree/main/off_chain_data) demuestra como construir un data store aguas abajo basado en los eventos de bloques.
|
||||
|
||||
### Leer-tus-propias-escrituras y conflictos
|
||||
|
||||
Las actualizaciones que una función transaccional hace al estado, no son realizadas inmediatamente; conforman un juego de cambios que deben ser endosados y ordenados. Este comportamiento asíncrono genera 2 consecuencias importantes.
|
||||
|
||||
Si la data bajo una clave es actualizada, y luego consultada *en la misma función del contrato inteligente* la data regresada sera el valor *original* - y no el valor actualizado.
|
||||
|
||||
Adicionalmente, puedes llegar a observar transacciones invalidadas con un error 'MVCC Conflict': esto significa que dos funciones transaccionales se ejecutaron al mismo tiempo y trataron de leer y actualizar las mismas claves. La primera transacción a ser ordenada en un bloque será validada, mientras que la segunda transacción será invalidada ya que la entrada de lectura ha cambiado desde la ejecución del contrato. Diseña tus claves y aplicaciones para que las mismas claves no sean actualizadas concurrentemente. Si esta es una ocurrencia inusual simplemente compénsala en la aplicación, por ejemplo, enviando nuevamente la transacción.
|
||||
|
||||
## Registro de Auditoría vs Registro de Activos
|
||||
|
||||
Una decisión importante a realizar es si el estado que se guarda en el ledger representa un 'registro de auditoría' de las actividades o la 'fuente de la verdad' del activo mismo. Como se observará en los ejemplos siguientes, almacenar la información de los activos es conceptualmente sencillo pero se debe tener en cuenta que esta es una base de datos distribuida mas que solo una base de datos.
|
||||
|
||||
Almacenar un tipo de registro de auditoría puede funcionar bien con el concepto de ledger. La 'fuente de la verdad' aquí es que cierta acción fue tomada y su resultado. Por ejemplo la propiedad de un activo cambió. Los detalles del activo en sí pueden ser almacenados fuera del ledger (off-chain). Esto si significa que se debe considerar mas infraestructura alrededor del ledger pero vale la pena contemplarlo si la principal justificación de negocio es el registro de auditoría. Por ejemplo, seguir el estado de un proceso y como se movió de un estado al siguiente.
|
||||
|
||||
Para ayudar con la integración de otros sistemas bien vale la pena emitir eventos desde la función transaccional. Estos eventos estarán disponibles para las aplicaciones cliente cuando la transacción este finalmente realizada. Estos pueden ser muy útiles para disparar otros procesos.
|
||||
|
||||
## ¿Es un Contrato Inteligente o un Chaincode?
|
||||
|
||||
Simplemente ambos - los términos han sido utilizados en la historia de Fabric casi que como equivalentes, Chaincode fue el nombre original, pero Contrato Inteligente es un término común en blockchain. La clase/estructura que ha sido extendida/implementada en el código se llama `Contract`.
|
||||
|
||||
El objetivo es estandarizar en:
|
||||
- los Contratos Inteligentes son las clases/estructuras - el código - que escribes en Go/JavaScript/TypeScript/Java etc.
|
||||
- éstos son luego empaquetadas y se ejecutan dentro de un contenedor de Chaincode (imagen de chaincode / ambiente de ejecución de chaincode dependiendo exactamente en el formato del paquete)
|
||||
- la definición del chaincode es más que tan solo el código del Contrato Inteligente, ya que incluye tales cosas como los índices de CouchDB, y la política de endoso.
|
||||
|
||||
## Empaquetado
|
||||
|
||||
En la versión 1.x de Hyperledger Fabric, y aún soportado como 'el ciclo de vida antiguo' en v2.x, el formato de paquete de chaincode CDS fue utilizado. El 'nuevo ciclo de vida' de v2.x debe ser utilizado de ahora en más - con el formato estándar `tar.gz`. Usar `tar` y `gzip` son técnicas estándar para herramientas estándar. Con lo cual la cuestión principal pasa a ser qué es lo que irá dentro de esos archivos y cuándo / cómo son usados.
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
# Comenzar con un Contrato Inteligente
|
||||
|
||||
[ANTERIOR - Introducción](./00-Introduction-ES.md) <==> [SIGUIENTE - Agregar una Función Transaccional](./02-Exercise-Adding-tx-function-ES.md)
|
||||
|
||||
---
|
||||
|
||||
Asegúrate de haber replicado/clonado el workshop:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/hyperledger/fabric-samples.git fabric-samples
|
||||
cd fabric-samples/full-stack-asset-transfer-guide
|
||||
|
||||
export WORKSHOP_PATH=$(pwd)
|
||||
```
|
||||
|
||||
Primero por favor revisa que tienes las [herramientas requeridas](../../SETUP.md) para la parte de dev de este workshop (docker, just, weft, node.js, y binario del Fabric peer). Para cerciorarse ejecuta el script `check.sh`
|
||||
|
||||
```
|
||||
${WORKSHOP_PATH}/check.sh
|
||||
```
|
||||
|
||||
Vayamos directo a crear el código para administrar un 'activo'; es mejor tener dos (2) ventanas abiertas, una para correr la 'FabricNetwork' y otra para 'ChaincodeDev'. Puedes querer abrir una tercera ventana para visualizar los logs de la red de Fabric.
|
||||
|
||||
## Inicia la Infraestructura de Fabric
|
||||
|
||||
Estamos utilizando MicroFab para la infraestructura de Fabric ya que es un único contenedor que es fácil de iniciar.
|
||||
El contenedor de MicroFab incluye un nodo del servicio de ordenamiento y un proceso peer que esta pre configurado para crear un channel e invocar chaincodes externos.
|
||||
Tiene ademas credenciales para una organización `org1`, que sera utilizada para ejecutar el peer. Usaremos un usuario administrador de `org1` para interactuar con el entorno.
|
||||
|
||||
Usaremos recetas de `just` para ejecutar múltiples comandos. Las recetas `just` son similares a make `make` pero mas fáciles de comprender. Puedes abrir el [justfile](../../justfile) en el directorio raíz del proyecto para ver qué comandos son ejecutados con cada receta.
|
||||
|
||||
Inicia el contenedor de MicroFab ejecutando la receta `just`. Esto establecerá algunas propiedades para el ambiente MicroFab e iniciará el contenedor docker de MicroFab.
|
||||
|
||||
```bash
|
||||
just microfab
|
||||
```
|
||||
|
||||
Esto arrancará el contenedor docker (lo descargara automáticamente si es necesario), y adicionalmente escribirá algunos archivos de configuración/data en el directorio `_cfg/uf`.
|
||||
```bash
|
||||
ls -1 _cfg/uf
|
||||
|
||||
_cfg
|
||||
_gateways
|
||||
_wallets
|
||||
org1admin.env
|
||||
org2admin.env
|
||||
```
|
||||
|
||||
Un archivo `org1admin.env` es generado que contiene las variables de entorno necesarias para ejecutar aplicaciones _con la identidad de org1 admin_. Una segunda organización es creada, con un `org2admin.env` - esto es para ejercicios más adelante y no es requerido para el actual.
|
||||
|
||||
Veamos cuáles son las variables de entorno y usemos source para establecer las mismas:
|
||||
|
||||
```bash
|
||||
source _cfg/uf/org1admin.env
|
||||
cat _cfg/uf/org1admin.env
|
||||
```
|
||||
|
||||
Veremos establecidas éstas variables de entorno:
|
||||
|
||||
```bash
|
||||
# valores de ejemplo
|
||||
export CORE_PEER_LOCALMSPID=org1MSP
|
||||
export CORE_PEER_MSPCONFIGPATH=/workshop/full-stack-asset-transfer-guide/_cfg/uf/_msp/org1/org1admin/msp
|
||||
export CORE_PEER_ADDRESS=org1peer-api.127-0-0-1.nip.io:8080
|
||||
export FABRIC_CFG_PATH=/workshop/full-stack-asset-transfer-guide/config
|
||||
export CORE_PEER_CLIENT_CONNTIMEOUT=15s
|
||||
export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s
|
||||
```
|
||||
|
||||
Ahora revisemos los tres directorios creados `_msp`, `_gateways`, `_wallets`. Si no tienes mucho tiempo puedes [saltear a la siguiente sección para empaquetar e implementar un chaincode](#empaquetar-e-implementar-el-chaincode-a-fabric).
|
||||
|
||||
Primero, el directorio `_msp` contiene los credenciales necesarios del membership services provider (MSP) para ejecutar los comandos CLI del Fabric Peer como org1 admin, incluyendo el certificado público del usuario y la llave privada para firmar las transacciones. La ubicación del MSP esta referenciado en la variable de entorno `CORE_PEER_MSGCONFIGPATH` y contiene los subdirectorios de credenciales que son esperados por el comando CLI del Peer.
|
||||
|
||||
En segundo lugar el directorio `_gateways` contiene dos archivos JSON, uno por organización. Este archivo contiene los detalles de la ruta url del Peer al que se pueden conectar los clientes. Los SDKs de clientes Fabric anteriores necesitaban que toda la información estuviese en este archivo, pero los nuevos "Gateway SDKs" quitaron la necesidad para tanto detalle. Los nuevos SDKs para Gateway solo necesitan la ruta del peer y su configuración de TLS. Puedes ver este [código ejemplo](../../applications/ping-chaincode/src/fabric-connection-profile.ts) para poder analizar este archivo fácilmente para el SDK de Gateway.
|
||||
|
||||
Por último esta el directorio `_wallets` - que tiene tres subdirectorios, uno para cada organización a saber la de Ordering, Organization 1, y Organization 2. Estos directorios contienen archivos `*.id` que tienen los detalles de identidades y sus respectivos credenciales, parecido al contenido del MSP, pero en un formato JSON que las aplicaciones pueden analizar fácilmente:
|
||||
|
||||
```
|
||||
_wallets
|
||||
├── Orderer
|
||||
│ └── ordereradmin.id
|
||||
├── org1
|
||||
│ ├── org1admin.id
|
||||
│ └── org1caadmin.id
|
||||
└── org2
|
||||
├── org2admin.id
|
||||
└── org2caadmin.id
|
||||
```
|
||||
|
||||
`org1admin.id` contiene los credenciales para enviar transacciones desde un administrador de org1.
|
||||
`org1caadmin.id` contiene los credenciales para crear identidades adicionales en la Autoridad Certificante (CA) de org1.
|
||||
|
||||
Tenga en cuenta que cuando Microfab comenzó lanzó automáticamente una Autoridad Certificante que creó estas identidades y sus respectivas credenciales.
|
||||
|
||||
Elija uno de los archivos de id y observa el contenido JSON del mismo incluyendo el certificado público y la llave privada:
|
||||
|
||||
```bash
|
||||
cat _cfg/uf/_wallets/org1/org1admin.id | jq
|
||||
```
|
||||
|
||||
Verás el contenido de org1admin.id:
|
||||
|
||||
```bash
|
||||
{
|
||||
"credentials": {
|
||||
"certificate": "-----BEGIN CERTIFICATE-----\n xxxx \n-----END CERTIFICATE-----\n",
|
||||
"privateKey": "-----BEGIN PRIVATE KEY-----\n xxxx \n-----END PRIVATE KEY-----\n"
|
||||
},
|
||||
"mspId": "org1MSP",
|
||||
"type": "X.509",
|
||||
"version": 1
|
||||
}
|
||||
```
|
||||
|
||||
Esta información puede ser utilizada por las aplicaciones cliente. Ver [este código ejemplo](../../applications/ping-chaincode/src/jsonid-adapter.ts) para entender como puedes analizar este archivo para usarlo con el gateway.
|
||||
|
||||
En este punto quizás quieras ejecutar `docker logs -f microfab` en una ventana separada para visualizar la actividad - no necesitas configurar nada específico aquí..
|
||||
|
||||
## Empaquetar e implementar el chaincode a Fabric
|
||||
|
||||
Utilizaremos el patrón Chaincode-As-A-Service (CCAAS) para este chaincode.
|
||||
Con este patrón, el peer de Fabric peer no inicia un chaincode implementado.
|
||||
En su lugar, ejecutaremos el chaincode como un proceso externo para que podamos fácilmente y localmente ejecutar los comandos para iniciarlo, detenerlo, actualizarlo y depurarlo.
|
||||
Sin embargo, aún debemos indicarle al peer dónde se esta ejecutando el chaincode. Esto lo logramos implementando un paquete de chaincode que incluye solamente, en vez del verdadero código fuente del mismo, el nombre del chaincode y la dirección del mismo.
|
||||
|
||||
### Empaquetar e implementar el chaincode utilizando la receta `just`.
|
||||
|
||||
```bash
|
||||
just debugcc
|
||||
```
|
||||
|
||||
Veras el id del chaincode y los pasos de implementación como resultado.
|
||||
|
||||
### Detalles de este proceso de empaquetar e implementar
|
||||
|
||||
Si te gustaría entender en mas detalle el proceso de empaquetar e implementar chaincodes puedes hacer manualmente los pasos a continuación. Caso contrario puedes [ir hacia adelante a la sección para ejecutar el chaincode](#ejecuta-el-chaincode-localmente).
|
||||
|
||||
Los paquetes de chaincode en Fabric son archivos en formato `tgz` que contienen dos archivos:
|
||||
|
||||
- `metadata.json` - la etiqueta y tipo del chaincode
|
||||
- `code.tar.gz` - artefactos fuentes del chaincode
|
||||
|
||||
Crea el archivo `metadata.json` primero, esto le indica al Peer el tipo de chaincode y la etiqueta a usar para referirse a él mas adelante.
|
||||
|
||||
```bash
|
||||
cat << METADATAJSON-EOF > metadata.json
|
||||
{
|
||||
"type": "ccaas",
|
||||
"label": "asset-transfer"
|
||||
}
|
||||
METADATAJSON-EOF
|
||||
```
|
||||
|
||||
Crea el archivo `code.tar.gz` - para el Chaincode-as-a-service, este archivo contendrá un solo archivo JSON `connection.json`. El proceso de empaquetar tradicional de Fabric incluiría aquí todo el código fuente del chaincode. En este caso, necesitamos que el archivo JSON contenga el URL donde el peer encontrará el chaincode y un limite de tiempo de espera. Note que este es un hostname especial para que el peer dentro del contenedor docker pueda localizar al chaincode ejecutándose en el sistema host.
|
||||
|
||||
```
|
||||
cat << CONNECTIONJSON-EOF > connection.json
|
||||
{
|
||||
"address":"host.docker.internal:9999",
|
||||
"dial_timeout":"15s"
|
||||
}
|
||||
CONNECTIONJSON-EOF
|
||||
```
|
||||
|
||||
Podemos ahora construir el paquete real. Crea un archivo code.tar.gz que contendrá el archivo connection.json.
|
||||
|
||||
```bash
|
||||
tar -czf code.tar.gz connection.json
|
||||
```
|
||||
|
||||
Crea el archivo empaquetado final del chaincode.
|
||||
|
||||
```bash
|
||||
tar -czf asset-transfer.tgz metadata.json code.tar.gz
|
||||
```
|
||||
|
||||
Utilizaremos los comandos CLI del peer para instalar e implementar el chaincode. Éste estará 'implementado' cuando se indique acuerdo para hacerlo y luego se asigne a un channel:
|
||||
|
||||
```
|
||||
source _cfg/uf/org1admin.env
|
||||
|
||||
peer lifecycle chaincode install asset-transfer.tgz
|
||||
```
|
||||
|
||||
El ChaincodeID que es devuelto por este comando de instalación debe ser almacenado, típicamente esto es mejor como una variable de entorno.
|
||||
|
||||
```bash
|
||||
export CHAINCODE_ID=$(peer lifecycle chaincode calculatepackageid asset-transfer.tgz)
|
||||
```
|
||||
|
||||
Paso siguiente, define el chaincode en el channel de blockchain aprobándolo y asignándoselo. Si ya lo has implementado utilizando la receta `just` de mas arriba, debes incrementar el número de `--sequence` a `2`.
|
||||
|
||||
```bash
|
||||
peer lifecycle chaincode approveformyorg --channelID mychannel --name asset-transfer -v 0 --package-id $CHAINCODE_ID --sequence 2 --connTimeout 15s
|
||||
peer lifecycle chaincode commit --channelID mychannel --name asset-transfer -v 0 --sequence 2 --connTimeout 15s
|
||||
```
|
||||
|
||||
## Ejecuta el chaincode localmente
|
||||
|
||||
Utilizaremos el contrato ejemplo en typescript ya escrito en `$WORKSHOP_PATH/contracts/asset-transfer-typescript`. Siéntete libre de revisar el código del contrato en [contracts/asset-transfer-typescript/src/assetTransfer.ts](../../contracts/asset-transfer-typescript/src/assetTransfer.ts). Podrás observar allí la implementación de funciones del contrato tales como `CreateAsset()` y `ReadAsset()`.
|
||||
|
||||
Utiliza otra ventana de terminal para el chaincode. Asegúrate que la terminal este definida con las mismas variables de entorno como en la primera terminal:
|
||||
|
||||
```
|
||||
cd fabric-samples/full-stack-asset-transfer-guide
|
||||
export WORKSHOP_PATH=$(pwd)
|
||||
export PATH=${WORKSHOP_PATH}/bin:$PATH
|
||||
export FABRIC_CFG_PATH=${WORKSHOP_PATH}/config
|
||||
```
|
||||
|
||||
Como con cualquier módulo en typescript debemos ejecutar `npm install` para administrar las dependencias del chaincode y luego construir (compilar) el código typescript del chaincode a javascript.
|
||||
|
||||
```
|
||||
cd contracts/asset-transfer-typescript
|
||||
|
||||
npm install
|
||||
|
||||
npm run build
|
||||
```
|
||||
|
||||
Una forma fácil de verificar que el contrato ha sido construido correctamente es generar la metadata del contrato ('Contract Metadata') en un archivo `metadata.json`. Esta es una definición del contrato y de los tipos de datos que éste retornó que es agnóstica a lenguajes. Toma prestado conceptos de OpenAPI utilizados en la definición de REST APIs. Es también muy útil para compartir con equipos que están escribiendo aplicaciones cliente para que conozcan la estructura de la data y las funciones de las transacciones que pueden invocar.
|
||||
Como es un documento JSON, puede ser utilizado para crear otros recursos.
|
||||
|
||||
El comando que genera la metadata ha sido colocado en el `package.json`:
|
||||
|
||||
```
|
||||
npm run metadata
|
||||
```
|
||||
|
||||
Revisa el archivo `metadata.json` generado y observa el resumen de la información del contrato, las funciones de transacciones y los tipos de datos. Esta información puede ser obtenida también en el momento de ejecución y es una buena forma de probar la implementación.
|
||||
|
||||
|
||||
## Desarrollo Iterativo y Pruebas
|
||||
|
||||
**Todos los pasos hasta ahora han sido por única vez. De aquí en adelante puedes iterar sobre el desarrollo de tu contrato**
|
||||
|
||||
Comencemos el módulo de tu nodo de Contrato Inteligente desde la ventana de terminal de tu contrato. Recuerda que el `CHAINCODE_ID` y el `CHAINCODE_SERVER_ADDRESS` son las únicas piezas de información que se necesita.
|
||||
|
||||
Nota: Usa tu específico CHAINCODE_ID obtenido anteriormente; el `CHAINCODE_SERVER_ADDRESS` es diferente - esto es porque en este caso lo esta indicando al chaincode donde escuchar a conexiones entrantes desde el Peer. Usaremos el puerto 9999 de la maquina local.
|
||||
|
||||
```
|
||||
source ${WORKSHOP_PATH}/_cfg/uf/org1admin.env
|
||||
|
||||
# si ejecutaste el justfile de arriba, estos valores ya estarán exportados, pero puedes querer verificar que tengan los siguientes valores:
|
||||
export CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999
|
||||
export CHAINCODE_ID=$(peer lifecycle chaincode calculatepackageid asset-transfer.tgz)
|
||||
|
||||
npm run start:server-debug
|
||||
```
|
||||
|
||||
### Ejecutar algunas transacciones
|
||||
|
||||
Elije una ventana de terminal desde donde ejecutar las transacciones; inicialmente utilizaremos el CLI del `peer` para ejecutar los comandos.
|
||||
|
||||
Si es una nueva ventana de terminal configura las variables de entorno:
|
||||
|
||||
```
|
||||
cd fabric-samples/full-stack-asset-transfer-guide
|
||||
export WORKSHOP_PATH=$(pwd)
|
||||
export PATH=${WORKSHOP_PATH}/bin:$PATH
|
||||
export FABRIC_CFG_PATH=${WORKSHOP_PATH}/config
|
||||
```
|
||||
|
||||
Asegúrate que tanto el binario del peer como el directorio config estén configurados (ejecuta el script `${WORKSHOP_PATH}/check.sh` para verificar).
|
||||
|
||||
Configura el contexto de ambiente para hacer de Administrador Org 1.
|
||||
|
||||
```
|
||||
source ${WORKSHOP_PATH}/_cfg/uf/org1admin.env
|
||||
```
|
||||
|
||||
Usa el CLI del peer para ejecutar comandos básicos de consulta contra el contrato. Por ejemplo, revisar la metadata del contrato (si tienes jq, es mas fácil leer si haces pipe de los resultados a jq). Usa uno de estos comandos:
|
||||
|
||||
```
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}'
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' | jq
|
||||
```
|
||||
|
||||
Creemos un activo con ID=001:
|
||||
|
||||
```
|
||||
peer chaincode invoke -C mychannel -n asset-transfer -c '{"Args":["CreateAsset","{\"ID\":\"001\", \"Color\":\"Red\",\"Size\":52,\"Owner\":\"Fred\",\"AppraisedValue\":234234}"]}' --connTimeout 15s
|
||||
```
|
||||
|
||||
Si estas observando los logs de MicroFab veras que el peer grabo un nuevo bloque al ledger.
|
||||
|
||||
Procede ahora a leer ese activo:
|
||||
|
||||
```
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["ReadAsset","001"]}'
|
||||
```
|
||||
|
||||
Veras que el activo es regresado:
|
||||
|
||||
```
|
||||
{"AppraisedValue":234234,"Color":"Red","ID":"001","Owner":"{\"org\":\"org1MSP\",\"user\":\"Fred\"}","Size":52}
|
||||
```
|
||||
|
||||
### Hacer un cambio y re-ejecutar el código
|
||||
|
||||
Si invocamos un comando de consulta en un activo que no existe, por ejemplo 002, obtendremos un error:
|
||||
|
||||
```
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["ReadAsset","002"]}'
|
||||
```
|
||||
|
||||
da un error:
|
||||
|
||||
```
|
||||
Error: endorsement failure during query. response: status:500 message:"Sorry, asset 002 has not been created"
|
||||
```
|
||||
|
||||
Supongamos que queremos cambiar ese mensaje de error por otra cosa.
|
||||
|
||||
- Detener el chaincode que se esta ejecutando (CTRL-C en la terminal del chaincode)
|
||||
- Abrir el archivo `src/assetTransfer.ts` en el editor de tu preferencia
|
||||
- Alrededor de la linea 51, encuentra el string del error y haz una modificación. Recuerda guardar el cambio.
|
||||
- Compila nuevamente el contrato en typescript:
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
Puedes arrancar nuevamente el contrato como hiciste antes
|
||||
|
||||
```
|
||||
npm run start:server-debug
|
||||
```
|
||||
|
||||
|
||||
Y ejecutar la misma consulta visualizando el mensaje de error actualizado:
|
||||
|
||||
```
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["ReadAsset","002"]}'
|
||||
```
|
||||
|
||||
## Depurar el código
|
||||
|
||||
Como el chaincode fue iniciado con la configuración de depuración de Node.js, se puede conectar al proceso un depurador de node.js. Por example VSCode trae un buen depurador de typescript/node.js.
|
||||
|
||||
Si seleccionas el tab de depurar, y abres las configuraciones de depuración, agrega la configuración "Asociar al proceso node".
|
||||
VSCode te mostrara el modelo. El puerto por defecto debería ser suficiente.
|
||||
Puedes entonces arrancar la depuración 'asociada al proceso', y seleccionar el proceso que se quiere depurar.
|
||||
|
||||
Recuerda establecer un punto de quiebre al comienzo de la función transaccional que quieres depurar.
|
||||
|
||||
Presta atención a:
|
||||
- VSCode usa node, así que ten cuidado para seleccionar el proceso correcto
|
||||
- recuerda que existe un límite de tiempo de la transacción cliente/fabric, mientras tengas al chaincode detenido en el depurador, el límite de tiempo sigue 'contando'
|
||||
|
||||
|
||||
Revisa [Probar y Depurar Contratos](./03-Test-And-Debug-Reference-ES.md) para mas detalles e información en otros lenguajes.
|
||||
|
|
@ -92,7 +92,7 @@ _wallets
|
|||
|
||||
Note that when MicroFab started it automatically launched a Certificate Authority that created these identities and their respective credentials.
|
||||
|
||||
Pick one if the id files and look at the JSON content including the public certificate and private key:
|
||||
Pick one of the id files and look at the JSON content including the public certificate and private key:
|
||||
|
||||
```bash
|
||||
cat _cfg/uf/_wallets/org1/org1admin.id | jq
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
## Agregar una Función Transaccional
|
||||
|
||||
[ANTERIOR - Comenzar](./01-Exercise-Getting-Started-ES.md) <==> [SIGUIENTE - Probar y Depurar](./03-Test-And-Debug-Reference-ES.md)
|
||||
|
||||
En este ejercicio, agregaremos una función transaccional para verificar el valor estimado. Escribiremos esta función como parte del ciclo de desarrollo iterativo de un chaincode-as-a-service externo, por lo cual no hay un requerimiento de detener Fabric o preocuparnos por las versiones implementadas del chaincode. Simplemente estaremos actualizando el código fuente del chaincode, reiniciando el servicio del chaincode, y probando la nueva función.
|
||||
|
||||
La función será:
|
||||
|
||||
- una función de 'solo-lectura'
|
||||
- esperará un id del activo y un valor superior e inferior
|
||||
- regresará una indicación por verdadero/false si el valor estimado se encuentra dentro de los valores superior e inferior
|
||||
|
||||
## Pasos
|
||||
|
||||
Asegúrate primero que has ejecutado el Contrato Inteligente y podido emitir transacciones contra él. Vale la pena cerciorarse que puedes detener y reiniciar el código luego de hacer cambios menores.
|
||||
|
||||
- En el archivo `assetTransfer.ts` crea una nueva función `ValidateValue`. La función `ReadAsset` es una buena función para usar como una base. Es una función de solo-lectura y ya obtiene el activo del ledger.
|
||||
- Agrega un valor superior e inferior a los parámetros de la función.
|
||||
- La función`ReadAsset` regresa directamente el activo, puedes mirar la función`UpdateAsset` para ver cómo procesar la data.
|
||||
- Verifica el valor y regresa verdadero/false dependiendo si el valor esta entre los límites o no.
|
||||
- Si quieres también puedes establecer un evento.
|
||||
|
||||
Recuerda detener el código que está ejecutándose, compilarlo e iniciarlo nuevamente. Recuerda que puedes anexar el depurador para ayudar a identificar los problemas.
|
||||
|
||||
## Probar
|
||||
|
||||
Puedes entonces invocar este código con comandos similares como en [Comenzar](./01-Exercise-Getting-Started-ES.md).
|
||||
|
||||
Por ejemplo para verificar que el valor este entre 1000 y 4200, puedes hacer el llamado similar a:
|
||||
|
||||
```
|
||||
peer chaincode query -C mychannel -n asset-transfer -c '{"Args":["ValidateValue","001","1000","4200"]}'
|
||||
```
|
||||
|
||||
## Ejemplo de implementación
|
||||
|
||||
Una implementación posible sería:
|
||||
|
||||
```
|
||||
@Transaction(false)
|
||||
async ValidateValue(ctx: Context, id: string, lower:number, upper:number): Promise<boolean> {
|
||||
const existingAssetBytes = await this.#readAsset(ctx, id);
|
||||
const existingAsset = newAsset(unmarshal(existingAssetBytes));
|
||||
|
||||
if (existingAsset.AppraisedValue > lower && existingAsset.AppraisedValue < upper){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# Referencia para Probar y Depurar
|
||||
|
||||
[ANTERIOR - Agregar una Función Transaccional](./02-Exercise-Adding-tx-function-ES.md)
|
||||
|
||||
**Meta:** Iniciar un Contrato Inteligente en Hyperledger Fabric para que pueda ser depurado fácilmente
|
||||
|
||||
**Objetivos:**
|
||||
|
||||
- Introducir qué es Chaincode-as-a-Service, y cómo ayuda
|
||||
- Mostrar cómo construir y configurar un Chaincode para ejecutar de esta manera
|
||||
- Cómo se implementan estos en una red que esta levantada de Hyperledger Fabric
|
||||
- Cómo depurar este Chaincode que se está ejecutando.
|
||||
|
||||
---
|
||||
|
||||
## Resumen
|
||||
|
||||
Ayuda pensar en estas tres 'partes':
|
||||
|
||||
- La red de Fabric, que consiste de los peers, ordenadores, autoridades certificantes etc. Junto con los channels configurados y las identidades.
|
||||
Para nuestros propósitos aquí, esto puede ser considerado como una 'caja negra'. La 'caja negra' puede ser configurada de maneras diferentes, pero típicamente será uno o mas contenedores docker. Este workshop usa MicroFab para levantar la red de Fabric en un único contenedor docker.
|
||||
- El Chaincode - que estará ejecutándose en su propio proceso o contenedor docker.
|
||||
- El editor - VSCode es usado aquí, pero el enfoque debería ser el mismo con otros depuradores y editores.
|
||||
|
||||
El _proceso a alto nivel_ es
|
||||
|
||||
0. Levantar Fabric
|
||||
1. Desarrollar el Contrato Inteligente
|
||||
3. Crear un paquete de chaincode utilizando el enfoque de chaincode-as-a-service
|
||||
4. Instalar el chaincode en un peer y Aprobar/Asignar el chaincode a un channel
|
||||
5. Iniciar el chaincode utilizando el enfoque chaincode-as-a-service
|
||||
6. Anexar el depurador al chaincode ejecutándose y definir un punto de quiebre
|
||||
7. Invocar una transacción, ésta se detendrá entonces en el depurador para que puedas pasar sobre el código
|
||||
8. Encontrar los errores y repetir **desde paso 5** - ten en cuenta que no necesitamos Empaquetar/Instalar/Aprobar/Asignar de nuevo el chaincode.
|
||||
|
||||
Este es el proceso exacto que habrás seguido en la sección ['Comenzar'](./01-Exercise-Getting-Started-ES.md).
|
||||
|
||||
### ¿Qué necesitas?
|
||||
|
||||
Necesitaras contar con disponibilidad de docker, junto con VSCode. Además instala las extensiones de VSCode que prefieres para depurar tu lenguaje de programación preferido. Existen otros depuradores disponibles y eres libre de usarlos si cuentas con ellos.
|
||||
|
||||
- Para TypeScript y JavaScript VSCode tiene el soporte incorporado
|
||||
- Para Java es sugerido el [paquete JavaExtension](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack).
|
||||
|
||||
### ¿Qué es Chaincode como un Servicio?
|
||||
|
||||
La facilidad de chaincode-as-a-service es una manera muy práctica y útil para ejecutar 'Contratos Inteligentes'. Tradicionalmente ha sido el Fabric Peer el que ha tomado el role de orquestar el ciclo de vida completo del chaincode. Esto requería acceso al Daemon de Docker para crear imágenes, e iniciar contenedores. Los marcos de chaincode programados en Java, Node.js y Go eran explícitamente conocidos por el peer incluyendo cómo debían ser compilados e iniciados.
|
||||
|
||||
Como resultado, esto hacía difícil implementar en entornos de estilo Kubernetes (K8S) o ejecutar de cualquier manera en modo depuración. Adicionalmente, el código esta siendo re compilado por el peer entonces existe cierto grado de incertidumbre respecto de qué dependencias deben ser incorporadas.
|
||||
|
||||
Hacer uso de chaincode-as-service requiere que sea uno quien orqueste la fase de compilación e implementación. Aunque esto es un paso adicional, devuelve el control. El Peer aún requiere que un 'paquete de chaincode' sea instalado. En este caso, éste no contiene código, pero si la información de dónde el chaincode esta hospedado (Hostname, Puerto, config de TLS, etc).
|
||||
|
||||
|
||||
## Ejecutar los Contratos Inteligentes
|
||||
|
||||
Un punto importante es que el código escrito para el Contrato Inteligente sea el mismo, sea que esté administrado por el peer o como Chaincode-as-a-Service.
|
||||
Lo que difiere es como es iniciado y empaquetado. El proceso global es el mismo, sin importar si el contrato inteligente este escrito en Java/Typescript/Go.
|
||||
|
||||
### TypeScript/JavaScript
|
||||
|
||||
Usando el contrato en Typescript como un ejemplo, se puede visualizar mejor la diferencia. El package.json contiene 4 comandos de 'start'.
|
||||
|
||||
```
|
||||
"start": "fabric-chaincode-node start",
|
||||
"start:server-nontls": "fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID",
|
||||
"start:server": "fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID --chaincode-tls-key-file=/hyperledger/privatekey.pem --chaincode-tls-client-cacert-file=/hyperledger/rootcert.pem --chaincode-tls-cert-file=/hyperledger/cert.pem",
|
||||
"start:server-debug": "set -x && NODE_OPTIONS='--inspect=0.0.0.0:9229' fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID"
|
||||
```
|
||||
|
||||
El primero es usado cuando el peer es quien controla completamente el chaincode. El segundo `start:server-nontls` se inicia en modo Chaincode-as-a-service (sin usar TLS). El comando es muy similar a `fabric-chaincode-node server` mas que `fabric-chaincode-node start`. Se proveen dos opciones aquí, que son, la dirección de red donde estará escuchando el chaincode y su id (aparte de cuando el Peer ejecuta el chaincode, si pasa opciones extras, pero no se pueden ver en el package.json).
|
||||
|
||||
El tercer `start:server` agrega la configuración TLS requerida, pero fuera de esto es igual.
|
||||
El cuarto `start:server-debug` es igual al caso de no-TLS, pero incluye la variable de entorno necesaria para que Node.js abra un puerto para permitirle al depurador conectarse remotamente.
|
||||
|
||||
### Java
|
||||
|
||||
Los cambios para los chaincode en Java son lógicamente los mismos. El build.gradle (o si deseas usa Maven) es exactamente igual (como si no hubiese cambios en la compilación de
|
||||
TypeScript). Con las librerías v2.4.1 de Chaincode en Java, no hay cambios en el código para hacer o compilar cambios. El modo '-as-a-service' será usado si esta definida la variable de entorno `CHAINCODE_SERVER_ADDRESS`.
|
||||
|
||||
Para el caso no-TLS el chaincode en Java es iniciado con `java -jar /chaincode.jar` - y usará el modo Chaincode-as-a-service _si_ esta definida la variable de entorno `CHAINCODE_SERVER_ADDRESS`.
|
||||
|
||||
Para depurar, la JVM necesita ser colocada en modo depuración `java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar`
|
||||
|
||||
## ¿En qué se diferencia el paquete de chaincode?
|
||||
|
||||
Una diferencia clave es que el paquete de chaincode no contiene código. Es utilizado como un contenedor de data que le indica al peer donde se encuentra el chaincode.
|
||||
¿Qué host/port y qué configuración TLS se necesitan? Los paquetes de chaincode ya contienen data respecto de los indices de CouchDB a usar o las colecciones de data privada.
|
||||
|
||||
Dentro del paquete, el archivo `connection.json` es importante. En su expresión mas simple sería:
|
||||
|
||||
```json
|
||||
{
|
||||
"address": "assettransfer_ccaas:9999",
|
||||
"dial_timeout": "10s",
|
||||
"tls_required": false
|
||||
}
|
||||
```
|
||||
|
||||
Esto le esta indicando al peer que el chaincode esta en el host `assettransfer_ccaas` puerto 9999. Define 10s como el tiempo de espera para conectarse y que TLS no es requerido.
|
||||
|
||||
El paquete puede ser construido manualmente, es un conjunto de archivos json, que se pueden juntar con `tgz`.
|
||||
|
||||
### Importante aviso de interconexión
|
||||
|
||||
El paquete del chaincode que es instalado críticamente contiene el nombre de red y puerto donde el peer espera que el chaincode este escuchando. Si nada contesta al peer, la transacción obviamente fallará.
|
||||
|
||||
Ten en cuenta que esta bien que el chaincode no se este ejecutando todo el tiempo, el peer no se quejará hasta que le sea efectivamente pedido conectarse al chaincode. Esta es una facilidad importante ya que permite que se pueda depurar y re iniciar el contenedor.
|
||||
|
||||
El nombre de red que es suministrado debe ser algo que el peer, desde su perspectiva, pueda resolver. Típicamente el peer se encontrará dentro de un contenedor docker, entonces proporcionar `localhost` o `127.0.0.1` resolverá al mismo contenedor donde esta ejecutándose el peer..
|
||||
|
||||
Asumiendo que el peer esta ejecutándose en un contenedor docker, el chaincode podría estar corriendo en su propio contenedor docker en la misma red de docker que el contenedor del peer, o podría estar ejecutándose directamente en el sistema host.
|
||||
|
||||
Dependiendo del sistema operativo de tu host, el 'specialhostname' que es usado desde dentro del contenedor docker para acceder al host varía.
|
||||
Por ejemplo, mira esto [stackoverflow post](https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach#:~:text=To%20access%20host%20machine%20from,using%20it%20to%20anything%20else.&text=Then%20make%20sure%20that%20you,0.0%20.)
|
||||
|
||||
La ventaja de esto es que el chaincode puede ejecutarse localmente en tu maquina host y es fácil conectarse al mismo desde un depurador.
|
||||
|
||||
Alternativamente, puedes empaquetar el chaincode en su propio contenedor docker, y ejecutar eso. Aún puedes conectarte para depurar pero debes asegurarte que los puertos del contenedor esten expuestos correctamente para el ambiente de ejecución de tu lenguaje.
|
||||
|
||||
## Paso individual y tiempos de espera
|
||||
|
||||
- Si vas a depurar paso a paso, entonces probablemente te topes con el valor del tiempo de espera de la transacción de Fabric. Por defecto este valor es de 30 segundos, que significa que el chaincode debe completar la transacción en 30 segundos o menos antes de que el peer limite el tiempo del requerimiento. En tu `config/core.yaml` actualiza `executetimeout` a `300s`, o agrega `CORE_CHAINCODE_EXECUTETIMEOUT=300s` a las variables de entorno de cada peer, para que puedas pasar por el código de tu contrato en un depurador por 5 minutos por función transaccional invocada.
|
||||
Loading…
Reference in a new issue