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
'sMsgSend
), 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 usaramino-json
para firmar la transacción usandoSIGN_MODE_LEGACY_AMINO_JSON
,--offline
: firma en modo offline. Esto significa que el comandotx 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 SignerInfo
s de todos los demás firmantes. Esto significa que necesitamos realizar dos pasos secuencialmente:
- para cada firmante, rellenar el
SignerInfo
del firmante dentro delTxBuilder
, - una vez que todos los
SignerInfo
s estén rellenados, para cada firmante, firmar elSignDoc
(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 SignerInfo
s, 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.