Pular para o conteúdo principal

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's MsgSend), 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_ADDRESS no 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 usar amino-json para assinar a transação usando SIGN_MODE_LEGACY_AMINO_JSON,
  • --offline: assinar no modo offline. Isso significa que o tx sign nã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-number e --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 SignerInfo do signatário dentro do TxBuilder,
  • uma vez que todos os SignerInfos estejam preenchidos, para cada signatário, assine o SignDoc (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.