Pular para o conteúdo principal

Enviando Transações

Na cadeia CrossFI, você pode enviar, assinar e transmitir transações das seguintes maneiras:

Usando o CLI

A melhor maneira de enviar transações é usando o CLI, como vimos na página anterior ao interagir com um nó. Por exemplo, executando o seguinte comando

crossfid tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000mpx

executará as seguintes etapas:

  • gerar uma transação com uma Msg (x/bank's MsgSend), e imprimir a transação gerada no console.
  • pedir confirmação do usuário para enviar a transação da conta $MY_VALIDATOR_ADDRESS.
  • buscar $MY_VALIDATOR_ADDRESS do keyring. Isto é possível porque configuramos o keyring do CLI em uma etapa anterior.
  • assinar a transação gerada com a conta do keyring.
  • transmitir a transação assinada para a rede. Isto é possível porque o CLI conecta-se ao endpoint RPC do nó Tendermint.

O CLI agrupa todas as etapas necessárias em uma experiência de usuário fácil de usar. No entanto, é possível executar todas as etapas individualmente também.

Gerando uma Transação

Gerar uma transação pode ser feito simplesmente adicionando a flag --generate-only em qualquer comando tx, por exemplo:

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

Isso exibirá a transação não assinada como JSON no console. Também podemos salvar a transação não assinada em um arquivo (para ser passada entre os signatários mais facilmente) adicionando > unsigned_tx.json ao comando acima.

Assinando uma Transação

Assinar uma transação usando o CLI requer que a transação não assinada seja salva em um arquivo. Vamos supor que a transação não assinada esteja em um arquivo chamado unsigned_tx.json no diretório atual (veja o parágrafo anterior para saber como fazer isso). Em seguida, basta executar 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 com a chave de $MY_VALIDATOR_ADDRESS, que já configuramos no keyring. A transação assinada será exibida como JSON no console e, como acima, podemos salvá-la em um arquivo adicionando > signed_tx.json.

Algumas flags úteis para considerar no comando tx sign:

  • --sign-mode: você pode usar amino-json para assinar a transação usando SIGN_MODE_LEGACY_AMINO_JSON,
  • --offline: assinar em modo offline. Isso significa que o comando tx sign não se conecta ao nó para recuperar o número da conta do signatário e a sequência, ambos necessários para assinar. Neste caso, você deve fornecer manualmente as flags --account-number e --sequence. Isso é útil para assinatura offline, ou seja, assinatura em um ambiente seguro que não tem acesso à internet.

Assinatura com Múltiplos Signatários

Observe que assinar uma transação com vários signatários ou com uma conta multisig, onde pelo menos um signatário usa SIGN_MODE_DIRECT, ainda não é possível. Você pode seguir esta questão do Github para mais informações.

Assinatura com múltiplos signatários é feita com o comando tx multisign. Este comando presume que todos os signatários usam SIGN_MODE_LEGACY_AMINO_JSON. O fluxo é similar 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 anexará assinaturas às transações existentes. É importante que os signatários assinem a transação na mesma ordem dada pela transação, que é recuperável usando o método GetSigners().

Por exemplo, começando com o unsigned_tx.json, e assumindo que a transação tem 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 para o signatário2.

# O signatário2 anexa sua assinatura:
crossfid tx multisign partial_tx_1.json signer_key_2 > partial_tx_2.json

# O signatário2 envia o arquivo partial_tx_2.json para o signatário3, e o signatário3 pode anexar sua assinatura:
crossfid tx multisign partial_tx_2.json signer_key_3 > partial_tx_3.json

Transmitindo uma Transação

A 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: o CLI aguarda que o tx seja confirmado em um bloco.
  • sync: o CLI aguarda apenas a resposta de execução do CheckTx.
  • async: o CLI retorna imediatamente (a transação pode falhar).

Codificando uma Transação

Para transmitir uma transação usando os endpoints gRPC ou REST, a transação precisará ser codificada primeiro. Isso pode ser feito usando o CLI.

Codificar uma transação é feito 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 como base64 no console.

Decodificando uma Transação

O CLI também pode ser usado para decodificar bytes de transação.

Decodificar uma transação é feito usando o seguinte comando:

crossfid tx decode [protobuf-byte-string]

Isso decodificará os bytes da transação e exibirá 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 através de Go usando a interface TxBuilder do Cosmos SDK.

Gerando uma Transação

Antes de gerar uma transação, uma nova instância de um TxBuilder precisa ser criada. Como o Cosmos SDK oferece suporte a transações Amino e Protobuf, o primeiro passo seria decidir qual esquema de codificação usar. Todas as etapas subsequentes permanecem inalteradas, independentemente de você estar usando Amino ou Protobuf, pois o TxBuilder abstrai os mecanismos de codificação. No snippet seguinte, usaremos Protobuf.

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

func sendTx() error

Podemos também configurar algumas chaves e endereços que enviarão e receberão as transações. Aqui, para fins de tutorial, usaremos alguns 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()

Preencher o TxBuilder pode ser feito através 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

Configuramos a configuração de codificação para usar Protobuf, que usará SIGN_MODE_DIRECT por padrão. Conforme ADR-020, cada signatário precisa assinar as SignerInfos de todos os outros signatários. Isso significa que precisamos realizar duas etapas sequencialmente:

  • para cada signatário, preencher o SignerInfo do signatário dentro do TxBuilder,
  • quando todas as SignerInfos estiverem preenchidas, para cada signatário, assinar o SignDoc (a carga a ser assinada).

Na atual API do TxBuilder, ambas as etapas são feitas usando o mesmo método: SetSignatures(). A API atual exige que primeiro façamos uma rodada de SetSignatures() com assinaturas vazias, apenas para preencher 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 das contas
accSeqs:= []uint64 // Os números de sequência das contas

// Primeira rodada: reunimos todas as informações dos signatários. Usamos o "truque de configurar assinatura vazia" 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 informações dos signatários estão configuradas, então 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 != nil
}

O TxBuilder agora está corretamente preenchido. Para imprimi-lo, você pode usar a interface TxConfig da configuração inicial de codificação 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 o CLI ou programaticamente com Go.

Transmitindo uma Transação

A transmissão de uma transação pelo endpoint gRPC pode ser feita enviando uma requisição BroadcastTx como a seguir, 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 o CLI ou programaticamente com Go.

Transmitindo uma Transação

A transmissão de uma transação pelo endpoint REST (servido por gRPC-gateway) pode ser feita enviando uma requisição POST como a seguir, 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 visa criar bibliotecas de clientes em JavaScript que podem ser incorporadas em aplicações web. Consulte https://cosmos.github.io/cosmjs para mais informações. Em janeiro de 2021, a documentação do CosmJS ainda estava em andamento.