Skip to main content

Envío de Transacciones

En la cadena CrossFI, puedes enviar, firmar y transmitir transacciones de las siguientes maneras:

Usando la CLI

La mejor manera de enviar transacciones es usar la CLI, como hemos visto en la página anterior al interactuar con un nodo. Por ejemplo, ejecutando el siguiente comando

crossfid tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000mpx

ejecutará los siguientes pasos:

  • generar una transacción con un Msg (x/bank's MsgSend), e imprimir la transacción generada en la consola.
  • pedir al usuario confirmación para enviar la transacción desde la cuenta $MY_VALIDATOR_ADDRESS.
  • obtener $MY_VALIDATOR_ADDRESS del almacén de claves. Esto es posible porque configuramos el almacén de claves de la CLI en un paso anterior.
  • firmar la transacción generada con la cuenta del almacén de claves.
  • transmitir la transacción firmada a la red. Esto es posible porque la CLI se conecta al punto final RPC de Tendermint del nodo.

La CLI agrupa todos los pasos necesarios en una experiencia de usuario fácil de usar. Sin embargo, también es posible ejecutar todos los pasos individualmente.

Generar una Transacción

Generar una transacción se puede hacer simplemente añadiendo la bandera --generate-only a cualquier comando tx, por ejemplo:

crossfid tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000mpx --generate-only

Esto emitirá la transacción sin firmar como JSON en la consola. También podemos guardar la transacción sin firmar en un archivo (para ser pasada entre firmantes más fácilmente) añadiendo > unsigned_tx.json al comando anterior.

Firmar una Transacción

Firmar una transacción usando la CLI requiere que la transacción sin firmar se guarde en un archivo. Supongamos que la transacción sin firmar está en un archivo llamado unsigned_tx.json en el directorio actual (vea el párrafo anterior sobre cómo hacerlo). Luego, simplemente ejecute el siguiente comando:

crossfid tx sign unsigned_tx.json --from $MY_VALIDATOR_ADDRESS

Este comando decodificará la transacción sin firmar y la firmará con SIGN_MODE_DIRECT con la clave de $MY_VALIDATOR_ADDRESS, que ya configuramos en el almacén de claves. La transacción firmada se emitirá como JSON en la consola y, como anteriormente, podemos guardarla en un archivo añadiendo > signed_tx.json.

Algunas banderas útiles a considerar en el comando tx sign:

  • --sign-mode: puedes usar amino-json para firmar la transacción usando SIGN_MODE_LEGACY_AMINO_JSON,
  • --offline: firma en modo offline. Esto significa que el comando tx sign no se conecta al nodo para recuperar el número de cuenta y secuencia del firmante, ambos necesarios para firmar. En este caso, debes proporcionar manualmente las banderas --account-number y --sequence. Esto es útil para firmar offline, es decir, firmar en un entorno seguro que no tiene acceso a internet.

Firmar con Múltiples Firmantes

Por favor, note que firmar una transacción con múltiples firmantes o con una cuenta de multisig, donde al menos un firmante use SIGN_MODE_DIRECT, aún no es posible. Puedes seguir este issue en Github para más información.

La firma con múltiples firmantes se realiza con el comando tx multisign. Este comando asume que todos los firmantes usan SIGN_MODE_LEGACY_AMINO_JSON. El flujo es similar al flujo del comando tx sign, pero en lugar de firmar un archivo de transacción sin firmar, cada firmante firma el archivo firmado por el (los) firmante(s) anterior(es).

El comando tx multisign añadirá firmas a las transacciones existentes. Es importante que los firmantes firmen la transacción en el mismo orden que se da en la transacción, la cual es recuperable usando el método GetSigners().

Por ejemplo, comenzando con el unsigned_tx.json, y asumiendo que la transacción tiene 4 firmantes, correríamos:


# Dejar que el firmante1 firme la tx sin firmar.
crossfid tx multisign unsigned_tx.json signer_key_1 > partial_tx_1.json

# Ahora el firmante1 enviará el partial_tx_1.json al firmante2.

# Firmante2 añade su firma:
crossfid tx multisign partial_tx_1.json signer_key_2 > partial_tx_2.json

# Firmante2 envía el archivo partial_tx_2.json al firmante3 y el firmante3 puede añadir su firma:
crossfid tx multisign partial_tx_2.json signer_key_3 > partial_tx_3.json

Transmitir una Transacción

La transmisión de una transacción se realiza usando el siguiente comando:

crossfid tx broadcast tx_signed.json

Puede opcionalmente pasar la bandera --broadcast-mode para especificar qué respuesta recibir del nodo:

  • block: la CLI espera a que la tx se comprometa en un bloque.
  • sync: la CLI espera solo una respuesta de ejecución de CheckTx.
  • async: la CLI regresa inmediatamente (la transacción podría fallar).

Codificación de una Transacción

Para transmitir una transacción usando los puntos finales gRPC o REST, primero la transacción debe ser codificada. Esto se puede hacer usando la CLI.

Codificación de una transacción se hace usando el siguiente comando:

crossfid tx encode tx_signed.json

Esto leerá la transacción del archivo, la serializará usando Protobuf y emitirá los bytes de transacción como base64 en la consola.

Decodificación de una Transacción

La CLI también puede usarse para decodificar bytes de transacciones.

La decodificación de una transacción se hace usando el siguiente comando:

crossfid tx decode [protobuf-byte-string]

Esto decodificará los bytes de la transacción y emitirá la transacción como JSON en la consola. También puedes guardar la transacción en un archivo añadiendo > tx.json al comando anterior.

Programáticamente con Go

Es posible manipular transacciones programáticamente a través de Go usando la interfaz TxBuilder del Cosmos SDK.

Generar una Transacción

Antes de generar una transacción, se necesita crear una nueva instancia de un TxBuilder. Dado que el Cosmos SDK admite tanto transacciones Amino como Protobuf, el primer paso sería decidir qué esquema de codificación usar. Todos los pasos posteriores permanecen sin cambios, ya sea que estés usando Amino o Protobuf, ya que TxBuilder abstrae los mecanismos de codificación. En el siguiente fragmento, utilizaremos Protobuf.

import (
"github.com/cosmos/cosmos-sdk/simapp"
)

func sendTx() error

También podemos configurar algunas claves y direcciones que enviarán y recibirán las transacciones. Aquí, a efectos del tutorial, utilizaremos algunos datos ficticios para crear claves.

import (
"github.com/cosmos/cosmos-sdk/testutil/testdata"
)

priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()

Poblar el TxBuilder se puede hacer a través de sus métodos:

import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func sendTx() error

txBuilder.SetGasLimit(...)
txBuilder.SetFeeAmount(...)
txBuilder.SetMemo(...)
txBuilder.SetTimeoutHeight(...)
}

En este punto, la transacción subyacente de TxBuilder está lista para ser firmada.

Firmar una Transacción

Configuramos la codificación para usar Protobuf, que usará SIGN_MODE_DIRECT por defecto. Según ADR-020, cada firmante necesita firmar las SignerInfos de todos los demás firmantes. Esto significa que necesitamos realizar dos pasos secuencialmente:

  • para cada firmante, rellenar el SignerInfo del firmante dentro del TxBuilder,
  • una vez que todos los SignerInfos estén rellenados, para cada firmante, firmar el SignDoc (la carga útil a firmar).

En la API actual de TxBuilder, ambos pasos se realizan usando el mismo método: SetSignatures(). La API actual nos requiere realizar primero una ronda de SetSignatures() con firmas vacías, solo para completar SignerInfos, y una segunda ronda de SetSignatures() para firmar efectivamente la carga útil correcta.

import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)

func sendTx() error
accNums:= []uint64 // Los números de cuenta de las cuentas
accSeqs:= []uint64 // Los números de secuencia de las cuentas

// Primera ronda: recopilamos toda la información del firmante. Usamos el truco de "establecer firma vacía" para hacerlo.
var sigsV2 []signing.SignatureV2
for i, priv := range privs ,
Sequence: accSeqs[i],
}

sigsV2 = append(sigsV2, sigV2)
}
err := txBuilder.SetSignatures(sigsV2...)
if err != nil

// Segunda ronda: toda la información del firmante está establecida, por lo que cada firmante puede firmar.
sigsV2 = []signing.SignatureV2{}
for i, priv := range privs
sigV2, err := tx.SignWithPrivKey(
encCfg.TxConfig.SignModeHandler().DefaultMode(), signerData,
txBuilder, priv, encCfg.TxConfig, accSeqs[i])
if err != nil

sigsV2 = append(sigsV2, sigV2)
}
err = txBuilder.SetSignatures(sigsV2...)
if err != nil
}

El TxBuilder está ahora correctamente poblado. Para imprimirlo, puedes usar la interfaz TxConfig de la configuración de codificación inicial encCfg:

func sendTx() error

// Generar una cadena JSON.
txJSONBytes, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil
txJSON := string(txJSONBytes)
}

Usando gRPC

No es posible generar o firmar una transacción usando gRPC, solo transmitirla. Para transmitir una transacción usando gRPC, necesitas generar, firmar y codificar la transacción usando ya sea la CLI o programáticamente con Go.

Transmitir una Transacción

Transmitir una transacción usando el punto final gRPC se puede hacer enviando una solicitud BroadcastTx como sigue, donde los txBytes son los bytes codificados en protobuf de una transacción firmada:

grpcurl -plaintext \
-d '}","mode":"BROADCAST_MODE_SYNC"}' \
localhost:9090 \
cosmos.tx.v1beta1.Service/BroadcastTx

Usando REST

No es posible generar o firmar una transacción usando REST, solo transmitirla. Para transmitir una transacción usando REST, necesitas generar, firmar y codificar la transacción usando ya sea la CLI o programáticamente con Go.

Transmitir una Transacción

Transmitir una transacción usando el punto final REST (servido por gRPC-gateway) se puede hacer enviando una solicitud POST como sigue, donde los txBytes son los bytes codificados en protobuf de una transacción firmada:

curl -X POST \
-H "Content-Type: application/json" \
-d'}","mode":"BROADCAST_MODE_SYNC"}' \
localhost:1317/cosmos/tx/v1beta1/txs

Usando CosmJS (JavaScript & TypeScript)

CosmJS tiene como objetivo crear bibliotecas de cliente en JavaScript que puedan ser incrustadas en aplicaciones web. Por favor, ver https://cosmos.github.io/cosmjs para más información. Desde enero de 2021, la documentación de CosmJS está en progreso.