Envio de Transações
Na CrossFI Chain, você pode enviar, assinar e transmitir transações das seguintes maneiras:
Usando a CLI
A melhor forma de enviar transações é usar a CLI, como vimos na página anterior ao interagir com um nó. Por exemplo, execute o seguinte comando:
crossfid tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000mpx
serão executados os seguintes passos:
- gerar uma transação com uma
Msg(x/bank'sMsgSend), e imprimir a transação gerada no console. - Solicitar ao usuário confirmação para enviar a transação a partir da conta
$MY_VALIDATOR_ADDRESS. - Buscar
$MY_VALIDATOR_ADDRESSno keyring. Isso é possível porque configuramos o keyring da CLI em uma etapa anterior. - assinar a transação gerada com a conta do keyring.
- transmitir a transação assinada para a rede. Isso é possível porque a CLI se conecta ao endpoint RPC Tendermint do nó.
A CLI agrega todas as etapas necessárias em uma experiência de usuário simples. No entanto, também é possível executar todas as etapas individualmente.
Gerando uma Transação
Gerar uma transação pode ser feito simplesmente ao adicionar a flag --generate-only a qualquer comando tx, por exemplo:
crossfid tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000mpx --generate-only
Isso imprimirá a transação não assinada como JSON no console. Também podemos salvar a transação não assinada em um arquivo (para facilitar o compartilhamento entre signers) adicionando > unsigned_tx.json ao comando acima.
Assinando uma Transação
Assinar uma transação usando a CLI requer que a transação não assinada seja salva em um arquivo. Suponha que a transação não assinada esteja em um arquivo chamado unsigned_tx.json no diretório atual (veja o parágrafo anterior sobre como fazer isso). Em seguida, execute simplesmente o seguinte comando:
crossfid tx sign unsigned_tx.json --from $MY_VALIDATOR_ADDRESS
Este comando decodificará a transação não assinada e a assinará com SIGN_MODE_DIRECT usando a chave da conta $MY_VALIDATOR_ADDRESS, que já configuramos no keyring. A transação assinada será impressa como JSON no console e, como acima, podemos salvá-la em um arquivo ao acrescentar > signed_tx.json.
Some useful flags to consider in the tx sign command:
--sign-mode: você pode usaramino-jsonpara assinar a transação usandoSIGN_MODE_LEGACY_AMINO_JSON,--offline: assinar no modo offline. Isso significa que otx signnão se conecta ao nó para recuperar o número de conta e a sequência do signatário. Nesse caso, você deve fornecer manualmente as flags--account-numbere--sequence. Isso é útil para assinatura offline, isto é, assinar em um ambiente seguro sem acesso à internet.
Assinando com Múltiplos Signatários
Observe que assinar uma transação com múltiplos signatários ou com uma conta multisig, em que pelo menos um signatário use SIGN_MODE_DIRECT, ainda não é possível. Você pode seguir este issue do Github para mais informações.
Assinatura com múltiplos signatários é feita com o tx multisign. Este comando assume que todos os signatários usam SIGN_MODE_LEGACY_AMINO_JSON. O fluxo é semelhante ao fluxo do comando tx sign, mas em vez de assinar um arquivo de transação não assinada, cada signatário assina o arquivo assinado pelo(s) signatário(s) anterior(es).
O comando tx multisign irá acrescentar assinaturas às transações existentes. É importante que os signatários assinem a transação na mesma ordem que a transação apresenta, a qual pode ser obtida usando o método GetSigners().
Por exemplo, começando com o unsigned_tx.json, e supondo que a transação tenha 4 signatários, executaríamos:
# Deixe o signatário1 assinar o tx não assinado.
crossfid tx multisign unsigned_tx.json signer_key_1 > partial_tx_1.json
# Agora o signatário1 enviará o partial_tx_1.json ao signatário2.
# O Signatário2 adiciona sua assinatura:
crossfid tx multisign partial_tx_1.json signer_key_2 > partial_tx_2.json
# O Signatário2 envia o partial_tx_2.json ao signatário3, e o signatário3 pode acrescentar sua assinatura:
crossfid tx multisign partial_tx_2.json signer_key_3 > partial_tx_3.json
Transmissão de uma Transação
Transmissão de uma transação é feita usando o seguinte comando:
crossfid tx broadcast tx_signed.json
Você pode opcionalmente passar a flag --broadcast-mode para especificar qual resposta receber do nó:
block: a CLI espera que a transação seja confirmada em um bloco.sync: a CLI espera pela resposta de execução do CheckTx apenas.async: a CLI retorna imediatamente (a transação pode falhar).
Codificação de uma Transação
Para transmitir uma transação usando os endpoints gRPC ou REST, a transação precisa ser codificada primeiro. Isso pode ser feito usando a CLI.
A codificação de uma transação é feita usando o seguinte comando:
crossfid tx encode tx_signed.json
Isso lerá a transação do arquivo, serializará usando Protobuf e exibirá os bytes da transação em base64 no console.
Decodificação de uma Transação
A CLI também pode ser usada para decodificar bytes de transação.
A decodificação de uma transação é feita usando o seguinte comando:
crossfid tx decode [protobuf-byte-string]
Isso decodificará os bytes da transação e imprimirá a transação como JSON no console. Você também pode salvar a transação em um arquivo, adicionando > tx.json ao comando acima.
Programaticamente com Go
É possível manipular transações programaticamente em Go usando a interface TxBuilder do Cosmos SDK.
Gerando uma Transação
Antes de gerar uma transação, é necessário criar uma nova instância de TxBuilder. Como o Cosmos SDK suporta tanto transações Amino quanto Protobuf, o primeiro passo é decidir qual esquema de codificação usar. Todas as etapas subsequentes permanecem inalteradas, quer você esteja usando Amino ou Protobuf, pois o TxBuilder abstrai os mecanismos de codificação. No trecho a seguir, usaremos Protobuf.
import (
"github.com/cosmos/cosmos-sdk/simapp"
)
func sendTx() error
Também podemos configurar algumas chaves e endereços que enviarão e receberão as transações. Aqui, para fins do tutorial, usaremos dados fictícios para criar chaves.
import (
"github.com/cosmos/cosmos-sdk/testutil/testdata"
)
priv1, _, addr1 := testdata.KeyTestPubAddr()
priv2, _, addr2 := testdata.KeyTestPubAddr()
priv3, _, addr3 := testdata.KeyTestPubAddr()
Populando o TxBuilder pode ser feito por meio de seus métodos:
import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
func sendTx() error
txBuilder.SetGasLimit(...)
txBuilder.SetFeeAmount(...)
txBuilder.SetMemo(...)
txBuilder.SetTimeoutHeight(...)
}
Neste ponto, a transação subjacente do TxBuilder está pronta para ser assinada.
Assinando uma Transação
Configuração de codificação para usar Protobuf, que usará SIGN_MODE_DIRECT por padrão. Conforme ADR-020, cada signatário precisa assinar os SignerInfos de todos os outros signatários. Isso significa que precisamos executar duas etapas sequencialmente:
- para cada signatário, preencher o
SignerInfodo signatário dentro doTxBuilder, - uma vez que todos os
SignerInfos estejam preenchidos, para cada signatário, assine oSignDoc(a carga a ser assinada).
Na API atual do TxBuilder, ambas as etapas são executadas usando o mesmo método: SetSignatures(). A API atual exige que façamos primeiro uma rodada de SetSignatures() com assinaturas vazias, apenas para popular SignerInfos, e uma segunda rodada de SetSignatures() para realmente assinar a carga correta.
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 // Os números de conta
accSeqs:= []uint64 // Os números de sequência
// Primeira rodada: reunimos todas as signer infos. Usamos a técnica de "assinar vazio" para fazer isso.
var sigsV2 []signing.SignatureV2
for i, priv := range privs ,
Sequence: accSeqs[i],
}
sigsV2 = append(sigsV2, sigV2)
}
err := txBuilder.SetSignatures(sigsV2...)
if err != nil
// Segunda rodada: todas as signer infos estão definidas, para cada signatário pode assinar.
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 !=n
}
O TxBuilder está agora preenchido corretamente. Para imprimi-lo, você pode usar a interface TxConfig da configuração de codificação inicial encCfg:
func sendTx() error
// Gerar uma string JSON.
txJSONBytes, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil
txJSON := string(txJSONBytes)
}
Usando gRPC
Não é possível gerar ou assinar uma transação usando gRPC, apenas transmiti-la. Para transmitir uma transação usando gRPC, você precisará gerar, assinar e codificar a transação usando a CLI ou programaticamente com Go.
Transmissão de uma Transação
Transmissão de uma transação usando o endpoint gRPC pode ser feita enviando uma requisição BroadcastTx conforme abaixo, onde os txBytes são os bytes codificados em protobuf de uma transação assinada:
grpcurl -plaintext \
-d '{"mode":"BROADCAST_MODE_SYNC"}' \
localhost:9090 \
cosmos.tx.v1beta1.Service/BroadcastTx
Usando REST
Não é possível gerar ou assinar uma transação usando REST, apenas transmiti-la. Para transmitir uma transação usando REST, você precisará gerar, assinar e codificar a transação usando a CLI ou programaticamente com Go.
Transmissão de uma Transação
Transmitir uma transação usando o endpoint REST (servido por gRPC-gateway) pode ser feito enviando uma requisição POST conforme abaixo, onde os txBytes são os bytes codificados em protobuf de uma transação assinada:
curl -X POST \
-H "Content-Type: application/json" \
-d'}","mode":"BROADCAST_MODE_SYNC"}' \
localhost:1317/cosmos/tx/v1beta1/txs
Usando CosmJS (JavaScript & TypeScript)
CosmJS tem como objetivo construir bibliotecas cliente em JavaScript que possam ser incorporadas em aplicações web. Consulte https://cosmos.github.io/cosmjs para mais informações. A documentação do CosmJS, até janeiro de 2021, ainda está em desenvolvimento.