From 0dd8553d522dd69d80acf514937425eead75da82 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 5 Jan 2021 15:45:35 +0100 Subject: [PATCH 01/11] Add structure of tx page --- docs/run-node/README.md | 5 +++-- docs/run-node/interact-node.md | 2 +- docs/run-node/txs.md | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 docs/run-node/txs.md diff --git a/docs/run-node/README.md b/docs/run-node/README.md index 9ff1d1666ae1..2ae01b8541e4 100644 --- a/docs/run-node/README.md +++ b/docs/run-node/README.md @@ -9,5 +9,6 @@ parent: This folder contains documentation on how to run a node and interact with it. 1. [Setting up the keyring](./keyring.md) -2. [Running a Node](./run-node.md) -3. [Interacting with a Node](./interact-node.md) +1. [Running a Node](./run-node.md) +1. [Interacting with a Node](./interact-node.md) +1. [Generating, Signing and Broadcasting Transactions](./txs.md) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index ca338c1313e3..adecea183196 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -117,7 +117,7 @@ Assuming the state at that block has not yet been pruned by the node, this query ### CosmJS -CosmJS documentation can be found at https://cosmos.github.io/cosmjs/. As of December 2020, CosmJS documentation is still work in progress. +CosmJS documentation can be found at [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs). As of December 2020, CosmJS documentation is still work in progress. ## Using the REST Endpoints diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md new file mode 100644 index 000000000000..bf7015fe2318 --- /dev/null +++ b/docs/run-node/txs.md @@ -0,0 +1,33 @@ + + +# Generating, Signing and Broadcasting Transactions + +This document describes how to generate, sign and broadcast a transaction. {synopsis} + +## Using the CLI + +The easiest way to send transactions is using the CLI, as we have seen in the previous page when [interacting with a node](./interact-node.md#using-the-cli). For example, running the following command + +```bash +simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain +``` + +will run the following steps: + +- generate a transaction with one `Msg` (`x/bank`'s `MsgSend`), and print the generated transaction to the console. +- ask the user for confirmation to send the transaction from the `$MY_VALIDATOR_ADDRESS` account. +- fetch `$MY_VALIDATOR_ADDRESS` in the keyring. This is possible because we have [set up the CLI's keyring](./keyring.md) in a previous step. +- sign the generated transaction with the keyring's account. +- broadcast the signed transaction to the network. This is possible because the CLI connects to the node's Tendermint RPC endpoint. + +The CLI bundles all the necessary steps into a simple-to-use user experience. In the next paragraphs, we will see how to perform these steps separately. + +## Generating a Transaction + +## Signing a Transaction + +## Broadcasting a Transaction + +### Simulation From 9c6c8790eef3b230e33705b316a38038fba3e537 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 12:38:02 +0100 Subject: [PATCH 02/11] WIP --- docs/run-node/txs.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index bf7015fe2318..47292406ecbd 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -4,7 +4,7 @@ order: 4 # Generating, Signing and Broadcasting Transactions -This document describes how to generate, sign and broadcast a transaction. {synopsis} +This document describes how to generate an (unsigned) transaction, signing it (with one or multiple keys), and broadcasting it to the network. {synopsis} ## Using the CLI @@ -22,12 +22,16 @@ will run the following steps: - sign the generated transaction with the keyring's account. - broadcast the signed transaction to the network. This is possible because the CLI connects to the node's Tendermint RPC endpoint. -The CLI bundles all the necessary steps into a simple-to-use user experience. In the next paragraphs, we will see how to perform these steps separately. +The CLI bundles all the necessary steps into a simple-to-use user experience. However, it's possible to run all the steps individually too. -## Generating a Transaction +### Generating a Transaction -## Signing a Transaction +Generating a transaction can simply be done by appending the `--generate-only` flag on any `tx` command, e.g.: -## Broadcasting a Transaction +```bash +simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain --generate-only +``` + +This will output the unsigned transaction as JSON in the console. -### Simulation +### Signing a Transaction From b9f27777425463f1c231d4d123dd0ca0510bb722 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 14:49:30 +0100 Subject: [PATCH 03/11] Finish CLI --- docs/run-node/interact-node.md | 2 +- docs/run-node/txs.md | 117 ++++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index adecea183196..b1b2cf506ac4 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -31,7 +31,7 @@ RECIPIENT=$(simd keys show recipient -a --keyring-backend test) The command above creates a local key-pair that is not yet registered on the chain. An account is created the first time it receives tokens from another account. Now, run the following command to send tokens to the `recipient` account: ```bash -simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain +simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain # Check that the recipient account did receive the tokens. simd query account $RECIPIENT --chain-id my-test-chain diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 47292406ecbd..74b8622a3fdd 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -11,7 +11,7 @@ This document describes how to generate an (unsigned) transaction, signing it (w The easiest way to send transactions is using the CLI, as we have seen in the previous page when [interacting with a node](./interact-node.md#using-the-cli). For example, running the following command ```bash -simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain +simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain ``` will run the following steps: @@ -29,9 +29,120 @@ The CLI bundles all the necessary steps into a simple-to-use user experience. Ho Generating a transaction can simply be done by appending the `--generate-only` flag on any `tx` command, e.g.: ```bash -simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain --generate-only +simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake --chain-id my-test-chain --generate-only ``` -This will output the unsigned transaction as JSON in the console. +This will output the unsigned transaction as JSON in the console. We can also save the unsigned transaction to a file (to be passed around between signers more easily) by appending `> unsigned_tx.json` to the above command. ### Signing a Transaction + +Signing a transaction using the CLI requires the unsigned transaction to be saved in a file. Let's assume the unsigned transaction is in a file called `unsigned_tx.json` in the current directory (see previous paragraph on how to save a transaction into a file). Then, simply run the following command: + +```bash +simd tx sign unsigned_tx.json --chain-id my-test-chain --keyring-backend test --from $MY_VALIDATOR_ADDRESS +``` + +This command will decode the unsigned transaction and sign it with `SIGN_MODE_DIRECT` with `$MY_VALIDATOR_ADDRESS`'s key, which we already set up in the keyring. The signed transaction will be output as JSON to the console, and, as above, we can save it to a file by appending `> signed_tx.json`. + +Some useful flags to consider in the `sign` command: + +- `--sign-mode`: you may use `amino-json` to sign the transaction using `SIGN_MODE_LEGACY_AMINO_JSON`, +- `--offline`: sign in offline mode. This means that the `sign` command doesn't connect to the node to retrieve the signer's account number and sequence, both needed for signing. In this case, you must manually supply the `--account-number` and `--sequence` flags. This is useful for offline signing, e.g. signing in a secure environment which doesn't have access to the internet. + +#### Signing with Multiple Signers + +::: warning +Please note that signing a transaction with multiple signers or with a multisig account, where at least one signer uses `SIGN_MODE_DIRECT`, is not possible as of yet. You may follow [this Github issue](https://github.com/cosmos/cosmos-sdk/issues/8141) for more info. +::: + +Signing with multiple signers is done with the `multisign` command. This command assumes that all signers use `SIGN_MODE_LEGACY_AMINO_JSON`. The flow is similar to the `sign` command flow, but instead of signing an unsigned transaction file, each signer signs the file signed by previous signers. The `multisign` command will append signatures to the existing transactions. It is important that signers sign the transaction **in the same order** as given by the transaction, which is retrievable using the `GetSigners()` method. + +For example, starting with the `unsigned_tx.json`, and assuming the transaction has 4 signers, we would run: + +```bash +# Let signer 1 sign the unsigned tx. +simd tx multisignsign unsigned_tx.json signer_key_1 --chain-id my-test-chain --keyring-backend test > partial_tx_1.json +# Signer 2 appends their signature. +simd tx multisignsign partial_tx_1.json signer_key_2 --chain-id my-test-chain --keyring-backend test > partial_tx_2.json +# Signer 3 appends their signature. +simd tx multisignsign partial_tx_2.json signer_key_3 --chain-id my-test-chain --keyring-backend test > partial_tx_3.json +# Signer 4 appends their signature. The final output is the fully signed tx. +simd tx multisignsign partial_tx_3.json signer_key_4 --chain-id my-test-chain --keyring-backend test > signed_tx.json +``` + +### Broadcasting a Transaction + +Broadcasting a transaction is done simply using the following command: + +```bash +simd tx broadcast tx_signed.json +``` + +You may optionally pass the `--broadcast-mode` flag to specify which response to receive from the node: + +- `block`: the CLI waits for the tx to be committed in a block. +- `sync`: the CLI waits for a CheckTx execution response only. +- `async`: the CLI returns immediately. + +## Programmatically with Go + +It is possible to manipulate transactions programmatically via Go using the Cosmos SDK's `TxBuilder` interface. + +### Generating a Transaction + +Before generating a transaction, a new instance of a `TxBuilder` needs to be created. Since the SDK supports both Amino and Protobuf transactions, the first step would be to decide which encoding scheme to use. All the subsequent steps remain unchanged, whether you're using Amino or Protobuf, as `TxBuilder` abstracts the encoding mechanisms. In the following snippet, we will use Protobuf. + +```go +import ( + "github.com/cosmos/cosmos-sdk/simapp" +) + +// Choose your codec: Amino or Protobuf. Here, we use Protobuf, given by the +// following function. +encCfg := simapp.MakeTestEncodingConfig() + +// Create a new TxBuilder. +txBuilder := encCfg.TxConfig.NewTxBuilder() +``` + +We can also set up some keys and addresses that will send and receive the transactions. Here, for the purpose of the tutorial, we will be using some dummy data to create keys. + +```go +import ( + "github.com/cosmos/cosmos-sdk/testutil/testdata" +) + +priv1, _, addr1 := testdata.KeyTestPubAddr() +priv2, _, addr2 := testdata.KeyTestPubAddr() +priv3, _, addr3 := testdata.KeyTestPubAddr() +``` + +Populating the `TxBuilder` can be done via its [methods](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/client/tx_config.go#L32-L45): + +```go +import ( + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// Define two x/bank MsgSend messages: +// - from addr1 to addr3, +// - from addr2 to addr3. +// This means that the transactions needs two signers: addr1 and addr2. +msg1 := banktypes.NewMsgSend(addr1, addr3, types.NewCoins(types.NewInt64Coin("atom", 12))) +msg2 := banktypes.NewMsgSend(addr2, addr3, types.NewCoins(types.NewInt64Coin("atom", 34))) + +err := txBuilder.SetMsgs(msg1, msg2) +if err != nil { + return err +} + +txBuilder.SetGasLimit(...) +txBuilder.SetFeeAmount(...) +txBuilder.SetMemo(...) +``` + +At this point, the `TxBuilder` is correctly populated, and the underlying transaction is ready to be signed. + +## Using CosmJS (JavaScript & TypeScript) + +CosmJS aims to build client libraries in JavaScript that can be embedded in web applications. Please see [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs) for more information. From 870a1895205f18737c32ff11d8eeac193832b27e Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 15:30:45 +0100 Subject: [PATCH 04/11] Add go examples --- docs/run-node/interact-node.md | 2 +- docs/run-node/txs.md | 167 ++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index b1b2cf506ac4..611d18dfe149 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -152,4 +152,4 @@ Assuming the state at that block has not yet been pruned by the node, this query ## Next {hide} -Sending transactions using gRPC and REST requires some additional steps: generating the transaction, signing it, and finally broadcasting it. Read about [generating and signing transactions](TODO https://github.com/cosmos/cosmos-sdk/issues/7657). {hide} +Sending transactions using gRPC and REST requires some additional steps: generating the transaction, signing it, and finally broadcasting it. Read about [generating and signing transactions](./txs.md). {hide} diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 74b8622a3fdd..6742096b4c1e 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -141,7 +141,172 @@ txBuilder.SetFeeAmount(...) txBuilder.SetMemo(...) ``` -At this point, the `TxBuilder` is correctly populated, and the underlying transaction is ready to be signed. +At this point, the `TxBuilder` is ready to be signed. + +### Signing a Transaction + +As per [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/docs/architecture/adr-020-protobuf-transaction-encoding.md), each signer needs to sign the `SignerInfo`s of all other signers. This means that we need to perform these two steps sequentially: + +- for each signer, populate the signer's `SignerInfo` inside `TxBuilder`, +- once all `SignerInfo` are populated, for each signer, sign the `SignDoc` (the payload to be signed). + +In the current `TxBuilder`'s API, both steps are done using the same method: `SetSignatures()`. The current API requires us to first perform a round of `SetSignatures()` _with empty signatures_, only to populate `SignerInfo`s, and a second round of `SetSignatures()` to actually sign the correct payload. + +```go +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" +) + +privs := []cryptotypes.PrivKey{priv1, priv2} +accNums:= []uint64{..., ...} // The accounts' account numbers +accSeqs:= []uint64{..., ...} // The accounts' sequence numbers + +// First round: we gather all the signer infos. We use the "set empty +// signature" hack to do that. +var sigsV2 []signing.SignatureV2 + +for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: encCfg.TxConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) +} +err := txBuilder.SetSignatures(sigsV2...) +if err != nil { + return err +} + +// Second round: all signer infos are set, so each signer can sign. +sigsV2 = []signing.SignatureV2{} +for i, priv := range privs { + signerData := xauthsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + sigV2, err := tx.SignWithPrivKey( + encCfg.TxConfig.SignModeHandler().DefaultMode(), signerData, + txBuilder, priv, encCfg.TxConfig, accSeqs[i]) + if err != nil { + return nil, err + } + + sigsV2 = append(sigsV2, sigV2) +} +err = txBuilder.SetSignatures(sigsV2...) +if err != nil { + return err +} +``` + +The `TxBuilder` is now correctly populated. To print it, you can use the `TxConfig` interface from the initial encoding config `encCfg`: + +```go +// Generated Protobuf-binary bytes. +txBytes, err := encCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) +if err != nil { + return err +} + +// Generate a JSON string. +txJSONBytes, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) +if err != nil { + return err +} +txJSON := string(txJSONBytes) +``` + +### Broadcasting a Transaction + +The preferred way to broadcast a transaction is to use gRPC, though using REST (via `gRPC-gateway`) or the Tendermint RPC is also posible. An overview of the differences between these methods is exposed [here](../core/grpc_rest.md). For this tutorial, we will only describe the gRPC method. + +```go +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + "github.com/cosmos/cosmos-sdk/types/tx" +) + +grpcConn := grpc.Dial( + val0.AppConfig.GRPC.Address, + grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism +) + +defer grpcConn.Close() + +// Broadcast the tx via gRPC. We create a new client for the Protobuf Tx +// service. +txClient := tx.NewServiceClient(s.conn) +// We then call the BroadcastTx method on this client. +grpcRes, err := txClient.BroadcastTx( + context.Background(), + &tx.BroadcastTxRequest{ + Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, + TxBytes: txBytes, // Proto-binary of the signed transaction, see previous step. + }, +) +if err != nil { + return err +} +fmt.Println(grpcRes.TxResponse.Code) // Should be `0` if the tx is successful +``` + +#### Simulating a Transaction + +Before broadcasting a transaction, we sometimes may want to dry-run the transaction, to estimate some information about the transaction without actually committing it. This is called simulating a transaction, and can be done as follows: + +```go +import ( + "context" + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/types/tx" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" +) + +// Simulate the tx via gRPC. We create a new client for the Protobuf Tx +// service. +txClient := tx.NewServiceClient(s.conn) +// We then call the BroadcastTx method on this client. +protoTx := txBuilderToProtoTx(txBuilder) +if err != nil { + return err +} +grpcRes, err := txClient.Simulate( + context.Background(), + &tx.SimulateRequest{ + Tx: protoTx, + }, +) +if err != nil { + return err +} + +fmt.Println(grpcRes.GasInfo) // Prints estimated gas used. + +// txBuilderToProtoTx converts a txBuilder into a proto tx.Tx. +func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint + protoProvider, ok := txBuilder.(authtx.ProtoTxProvider) + if !ok { + return nil, fmt.Errorf("expected proto tx builder, got %T", txBuilder) + } + + return protoProvider.GetProtoTx(), nil +} +``` ## Using CosmJS (JavaScript & TypeScript) From c895e9e19b0dee79d5c95d60c8eba1b771356a79 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 15:47:57 +0100 Subject: [PATCH 05/11] Add golang examples --- docs/run-node/interact-node.md | 80 ++++++++++++++++++++++++++++++++-- docs/run-node/txs.md | 12 ++--- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index 611d18dfe149..9c47dce6aac0 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -52,12 +52,13 @@ You should see two delegations, the first one made from the `gentx`, and the sec The Protobuf ecosystem developed tools for different use cases, including code-generation from `*.proto` files into various languages. These tools allow to build clients easily. Often, the client connection (i.e. the transport) can be plugged and replaced very easily. Let's explore one of the most popular transport: [gRPC](../core/grpc_rest.md). -Since the code generation library largely depends on your own tech stack, we will only present two alternatives: +Since the code generation library largely depends on your own tech stack, we will only present three alternatives: - `grpcurl` for generic debugging and testing, +- programmatically via Go, - CosmJS for JavaScript/TypeScript developers. -### grpcurl: Reflection, Queries, and Simulation +### grpcurl [grpcurl])https://github.com/fullstorydev/grpcurl is like `curl` but for gRPC. It is also available as a Go library, but we will use it only as a CLI command for debugging and testing purposes. Follow the instructions in the previous link to install it. @@ -97,7 +98,7 @@ grpcurl \ The list of all available gRPC query endpoints is [coming soon](https://github.com/cosmos/cosmos-sdk/issues/7786). -### Query for historical state using gRPC +#### Query for historical state using grpcurl You may also query for historical data by passing some [gRPC metadata](https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md) to the query: the `x-cosmos-block-height` metadata should contain the block to query. Using grpcurl as above, the command looks like: @@ -115,9 +116,80 @@ grpcurl \ Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response. +### Programmtically via Go + +The following snippet shows how to + +```go +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +myAddress, err := sdk.AccAddressFromBech32("cosmos1...") +if err != nil { + return err +} + +grpcConn := grpc.Dial( + "127.0.0.1:9090", // Or your gRPC server address. + grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. +) +defer grpcConn.Close() + +// gRPC query to x/bank service. +bankClient := banktypes.NewQueryClient(grpcConn) +bankRes, err := bankClient.Balance( + context.Background(), + &banktypes.QueryBalanceRequest{Address: myAddress, Denom: "atom"}, +) +if err != nil { + return err +} + +fmt.Println(bankRes.GetBalance()) // Prints the account balance +``` + +You can replace the query client (here, `x/bank`) with the one from any other Protobuf service. The list of all available gRPC query endpoints is [coming soon](https://github.com/cosmos/cosmos-sdk/issues/7786). + +#### Query for historical state using Go + +Querying for historical blocks is done by adding the block height metadata in the gRPC request. + +```go +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +var header metadata.MD +bankRes, err = bankClient.Balance( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, "12"), // Add metadata to request + &banktypes.QueryBalanceRequest{Address: myAddress, Denom: denom}, + grpc.Header(&header), // Retrieve header from response +) +if err != nil { + return err +} +blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader) + +fmt.Println(blockHeight) // Prints the block height (12) +``` + ### CosmJS -CosmJS documentation can be found at [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs). As of December 2020, CosmJS documentation is still work in progress. +CosmJS documentation can be found at [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs). As of As of January 2021, CosmJS documentation is still work in progress. ## Using the REST Endpoints diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 6742096b4c1e..8caf2bda9146 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -239,15 +239,14 @@ import ( ) grpcConn := grpc.Dial( - val0.AppConfig.GRPC.Address, - grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism + "127.0.0.1:9090", // Or your gRPC server address. + grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. ) - defer grpcConn.Close() // Broadcast the tx via gRPC. We create a new client for the Protobuf Tx // service. -txClient := tx.NewServiceClient(s.conn) +txClient := tx.NewServiceClient(grpcConn) // We then call the BroadcastTx method on this client. grpcRes, err := txClient.BroadcastTx( context.Background(), @@ -259,6 +258,7 @@ grpcRes, err := txClient.BroadcastTx( if err != nil { return err } + fmt.Println(grpcRes.TxResponse.Code) // Should be `0` if the tx is successful ``` @@ -279,7 +279,7 @@ import ( // Simulate the tx via gRPC. We create a new client for the Protobuf Tx // service. -txClient := tx.NewServiceClient(s.conn) +txClient := tx.NewServiceClient(grpcConn) // We then call the BroadcastTx method on this client. protoTx := txBuilderToProtoTx(txBuilder) if err != nil { @@ -310,4 +310,4 @@ func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint ## Using CosmJS (JavaScript & TypeScript) -CosmJS aims to build client libraries in JavaScript that can be embedded in web applications. Please see [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs) for more information. +CosmJS aims to build client libraries in JavaScript that can be embedded in web applications. Please see [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs) for more information. As of January 2021, CosmJS documentation is still work in progress. From a0f19e86ec23208b4feea226cfae4a7b3e7dde5b Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 16:03:07 +0100 Subject: [PATCH 06/11] Tweaks --- docs/run-node/interact-node.md | 7 ++++--- docs/run-node/txs.md | 23 ++++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index 9c47dce6aac0..e1c6ad47ec8a 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -118,7 +118,7 @@ Assuming the state at that block has not yet been pruned by the node, this query ### Programmtically via Go -The following snippet shows how to +The following snippet shows how to query the state using gRPC inside a Go program. The idea is to create a gRPC connection, and use the Protobuf-generated client code to query the gRPC server. ```go import ( @@ -136,13 +136,14 @@ if err != nil { return err } +// Create a connection to the gRPC server. grpcConn := grpc.Dial( "127.0.0.1:9090", // Or your gRPC server address. grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. ) defer grpcConn.Close() -// gRPC query to x/bank service. +// This creates a gRPC client to query the x/bank service. bankClient := banktypes.NewQueryClient(grpcConn) bankRes, err := bankClient.Balance( context.Background(), @@ -155,7 +156,7 @@ if err != nil { fmt.Println(bankRes.GetBalance()) // Prints the account balance ``` -You can replace the query client (here, `x/bank`) with the one from any other Protobuf service. The list of all available gRPC query endpoints is [coming soon](https://github.com/cosmos/cosmos-sdk/issues/7786). +You can replace the query client (here we are using `x/bank`'s) with one generated from any other Protobuf service. The list of all available gRPC query endpoints is [coming soon](https://github.com/cosmos/cosmos-sdk/issues/7786). #### Query for historical state using Go diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 8caf2bda9146..04299aa95862 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -36,7 +36,7 @@ This will output the unsigned transaction as JSON in the console. We can also sa ### Signing a Transaction -Signing a transaction using the CLI requires the unsigned transaction to be saved in a file. Let's assume the unsigned transaction is in a file called `unsigned_tx.json` in the current directory (see previous paragraph on how to save a transaction into a file). Then, simply run the following command: +Signing a transaction using the CLI requires the unsigned transaction to be saved in a file. Let's assume the unsigned transaction is in a file called `unsigned_tx.json` in the current directory (see previous paragraph on how to do that). Then, simply run the following command: ```bash simd tx sign unsigned_tx.json --chain-id my-test-chain --keyring-backend test --from $MY_VALIDATOR_ADDRESS @@ -44,10 +44,10 @@ simd tx sign unsigned_tx.json --chain-id my-test-chain --keyring-backend test -- This command will decode the unsigned transaction and sign it with `SIGN_MODE_DIRECT` with `$MY_VALIDATOR_ADDRESS`'s key, which we already set up in the keyring. The signed transaction will be output as JSON to the console, and, as above, we can save it to a file by appending `> signed_tx.json`. -Some useful flags to consider in the `sign` command: +Some useful flags to consider in the `tx sign` command: - `--sign-mode`: you may use `amino-json` to sign the transaction using `SIGN_MODE_LEGACY_AMINO_JSON`, -- `--offline`: sign in offline mode. This means that the `sign` command doesn't connect to the node to retrieve the signer's account number and sequence, both needed for signing. In this case, you must manually supply the `--account-number` and `--sequence` flags. This is useful for offline signing, e.g. signing in a secure environment which doesn't have access to the internet. +- `--offline`: sign in offline mode. This means that the `tx sign` command doesn't connect to the node to retrieve the signer's account number and sequence, both needed for signing. In this case, you must manually supply the `--account-number` and `--sequence` flags. This is useful for offline signing, i.e. signing in a secure environment which doesn't have access to the internet. #### Signing with Multiple Signers @@ -55,7 +55,7 @@ Some useful flags to consider in the `sign` command: Please note that signing a transaction with multiple signers or with a multisig account, where at least one signer uses `SIGN_MODE_DIRECT`, is not possible as of yet. You may follow [this Github issue](https://github.com/cosmos/cosmos-sdk/issues/8141) for more info. ::: -Signing with multiple signers is done with the `multisign` command. This command assumes that all signers use `SIGN_MODE_LEGACY_AMINO_JSON`. The flow is similar to the `sign` command flow, but instead of signing an unsigned transaction file, each signer signs the file signed by previous signers. The `multisign` command will append signatures to the existing transactions. It is important that signers sign the transaction **in the same order** as given by the transaction, which is retrievable using the `GetSigners()` method. +Signing with multiple signers is done with the `tx multisign` command. This command assumes that all signers use `SIGN_MODE_LEGACY_AMINO_JSON`. The flow is similar to the `tx sign` command flow, but instead of signing an unsigned transaction file, each signer signs the file signed by previous signer(s). The `tx multisign` command will append signatures to the existing transactions. It is important that signers sign the transaction **in the same order** as given by the transaction, which is retrievable using the `GetSigners()` method. For example, starting with the `unsigned_tx.json`, and assuming the transaction has 4 signers, we would run: @@ -72,7 +72,7 @@ simd tx multisignsign partial_tx_3.json signer_key_4 --chain-id my-test-chain -- ### Broadcasting a Transaction -Broadcasting a transaction is done simply using the following command: +Broadcasting a transaction is done using the following command: ```bash simd tx broadcast tx_signed.json @@ -82,7 +82,7 @@ You may optionally pass the `--broadcast-mode` flag to specify which response to - `block`: the CLI waits for the tx to be committed in a block. - `sync`: the CLI waits for a CheckTx execution response only. -- `async`: the CLI returns immediately. +- `async`: the CLI returns immediately (transaction might fail). ## Programmatically with Go @@ -139,16 +139,17 @@ if err != nil { txBuilder.SetGasLimit(...) txBuilder.SetFeeAmount(...) txBuilder.SetMemo(...) +txBuilder.SetTimeoutHeight(...) ``` -At this point, the `TxBuilder` is ready to be signed. +At this point, `TxBuilder`'s underlying transaction is ready to be signed. ### Signing a Transaction -As per [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/docs/architecture/adr-020-protobuf-transaction-encoding.md), each signer needs to sign the `SignerInfo`s of all other signers. This means that we need to perform these two steps sequentially: +We chose our encoding config to use Protobuf, which will use `SIGN_MODE_DIRECT` by default. As per [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/docs/architecture/adr-020-protobuf-transaction-encoding.md), each signer needs to sign the `SignerInfo`s of all other signers. This means that we need to perform two steps sequentially: - for each signer, populate the signer's `SignerInfo` inside `TxBuilder`, -- once all `SignerInfo` are populated, for each signer, sign the `SignDoc` (the payload to be signed). +- once all `SignerInfo`s are populated, for each signer, sign the `SignDoc` (the payload to be signed). In the current `TxBuilder`'s API, both steps are done using the same method: `SetSignatures()`. The current API requires us to first perform a round of `SetSignatures()` _with empty signatures_, only to populate `SignerInfo`s, and a second round of `SetSignatures()` to actually sign the correct payload. @@ -166,7 +167,6 @@ accSeqs:= []uint64{..., ...} // The accounts' sequence numbers // First round: we gather all the signer infos. We use the "set empty // signature" hack to do that. var sigsV2 []signing.SignatureV2 - for i, priv := range privs { sigV2 := signing.SignatureV2{ PubKey: priv.PubKey(), @@ -210,7 +210,7 @@ if err != nil { The `TxBuilder` is now correctly populated. To print it, you can use the `TxConfig` interface from the initial encoding config `encCfg`: ```go -// Generated Protobuf-binary bytes. +// Generated Protobuf-encoded bytes. txBytes, err := encCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) if err != nil { return err @@ -238,6 +238,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" ) +// Create a connection to the gRPC server. grpcConn := grpc.Dial( "127.0.0.1:9090", // Or your gRPC server address. grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. From 4aad5280237012ddbc892b5fc741dcee4722cdff Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 6 Jan 2021 16:18:10 +0100 Subject: [PATCH 07/11] Update links --- docs/core/transactions.md | 4 ++-- docs/migrations/rest.md | 4 ++-- docs/run-node/txs.md | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/core/transactions.md b/docs/core/transactions.md index 581a8a4de021..529fd0d17ab8 100644 --- a/docs/core/transactions.md +++ b/docs/core/transactions.md @@ -141,13 +141,13 @@ simd tx send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000stake The `Tx` service exposes a handful of utility functions, such as simulating a transaction or querying a transaction, and also one method to broadcast transactions. -An example of broadcasting a transaction is shown in [TODO](https://github.com/cosmos/cosmos-sdk/issues/7657). +Examples of broadcasting and simulating a transaction are shown [here](../run-node/txs.md#programmatically-with-go). #### REST Each gRPC method has its corresponding REST endpoint, generated using [gRPC-gateway](https://github.com/grpc-ecosystem/grpc-gateway). Therefore, instead of using gRPC, you can also use HTTP to broadcast the same transaction, on the `POST /cosmos/tx/v1beta1/txs` endpoint. -An example can be seen [here TODO](https://github.com/cosmos/cosmos-sdk/issues/7657) +An example can be seen [here](../run-node/txs.md#using-rest) #### Tendermint RPC diff --git a/docs/migrations/rest.md b/docs/migrations/rest.md index d62ef9a44f38..2bb28dbba628 100644 --- a/docs/migrations/rest.md +++ b/docs/migrations/rest.md @@ -34,7 +34,7 @@ Some important information concerning all legacy REST endpoints: Thanks to the Protocol Buffers migration in v0.40 we are able to take advantage of a vast number of gRPC tools and solutions. For most of the legacy REST endpoints, Cosmos SDK v0.40 provides new REST endpoints generated from [gRPC `Query` services](../building-modules/query-services.md) using [grpc-gateway](https://grpc-ecosystem.github.io/grpc-gateway/). We usually call them _gGPC-gateway REST endpoints_. -Some modules expose legacy `POST` endpoints to generate unsigned transactions for their `Msg`s. These `POST` endpoints have been removed. We recommend to use [service `Msg`s](../building-modules/msg-services.md) directly, and use Protobuf to do client-side transaction generation. A guide can be found [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657). +Some modules expose legacy `POST` endpoints to generate unsigned transactions for their `Msg`s. These `POST` endpoints have been removed. We recommend to use [service `Msg`s](../building-modules/msg-services.md) directly, and use Protobuf to do client-side transaction generation. A guide can be found [here](../run-node/txs.md). | Legacy REST Endpoint | Description | New gGPC-gateway REST Endpoint | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | @@ -98,4 +98,4 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo ## Migrating to gRPC -Instead of hitting REST endpoints as described in the previous paragraph, the SDK also exposes a gRPC server. Any client can use gRPC instead of REST to interact with the node. An overview of different ways to communicate with a node can be found [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657), and a concrete tutorial for setting up a gRPC client [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657). +Instead of hitting REST endpoints as described in the previous paragraph, the SDK also exposes a gRPC server. Any client can use gRPC instead of REST to interact with the node. An overview of different ways to communicate with a node can be found [here](../core/grpc_rest.md), and a concrete tutorial for setting up a gRPC client [here](../run-node/txs.md#programmatically-with-go). diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 04299aa95862..0ac96c64f19d 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -309,6 +309,21 @@ func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint } ``` +## Using REST + +It is not possible to generate or sign a transaction using REST, only to broadcast one. + +### Broadcasting a Transaction + +Broadcasting a transaction using the REST endpoint (served by `gRPC-gateway`) can be done by sending a POST request as follows, where the `txBytes` are the protobuf-encoded bytes of a signed transaction: + +```bash +curl -X POST \ + -H "Content-Type: application/json" + -d'{"tx_bytes":"{{txBytes}}","mode":"BROADCAST_MODE_SYNC"}' + localhost:1317/cosmos/tx/v1beta1/txs +``` + ## Using CosmJS (JavaScript & TypeScript) CosmJS aims to build client libraries in JavaScript that can be embedded in web applications. Please see [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs) for more information. As of January 2021, CosmJS documentation is still work in progress. From 4902d7d0cb922fb0044a67f9c19c1580c8b30f06 Mon Sep 17 00:00:00 2001 From: Amaury Date: Thu, 7 Jan 2021 16:24:37 +0100 Subject: [PATCH 08/11] Update docs/run-node/interact-node.md Co-authored-by: Marie Gauthier --- docs/run-node/interact-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index e1c6ad47ec8a..1051af6072fa 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -190,7 +190,7 @@ fmt.Println(blockHeight) // Prints the block height (12) ### CosmJS -CosmJS documentation can be found at [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs). As of As of January 2021, CosmJS documentation is still work in progress. +CosmJS documentation can be found at [https://cosmos.github.io/cosmjs](https://cosmos.github.io/cosmjs). As of January 2021, CosmJS documentation is still work in progress. ## Using the REST Endpoints From 50961d235adf4e234ec53de3be128310cf86caa1 Mon Sep 17 00:00:00 2001 From: Amaury Date: Thu, 7 Jan 2021 16:24:44 +0100 Subject: [PATCH 09/11] Update docs/run-node/interact-node.md Co-authored-by: Marie Gauthier --- docs/run-node/interact-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index 1051af6072fa..74022c141394 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -116,7 +116,7 @@ grpcurl \ Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response. -### Programmtically via Go +### Programmatically via Go The following snippet shows how to query the state using gRPC inside a Go program. The idea is to create a gRPC connection, and use the Protobuf-generated client code to query the gRPC server. From 8ec4061eb40d891ac16a0b53ca74ee2ded53a7e7 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 7 Jan 2021 17:14:44 +0100 Subject: [PATCH 10/11] Put code snippets in functiosn --- docs/run-node/interact-node.md | 48 ++++--- docs/run-node/txs.md | 244 ++++++++++++++++++--------------- 2 files changed, 162 insertions(+), 130 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index e1c6ad47ec8a..d38cd5acf673 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -131,29 +131,33 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" ) -myAddress, err := sdk.AccAddressFromBech32("cosmos1...") -if err != nil { - return err -} - -// Create a connection to the gRPC server. -grpcConn := grpc.Dial( - "127.0.0.1:9090", // Or your gRPC server address. - grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. -) -defer grpcConn.Close() - -// This creates a gRPC client to query the x/bank service. -bankClient := banktypes.NewQueryClient(grpcConn) -bankRes, err := bankClient.Balance( - context.Background(), - &banktypes.QueryBalanceRequest{Address: myAddress, Denom: "atom"}, -) -if err != nil { - return err +func queryState() error { + myAddress, err := sdk.AccAddressFromBech32("cosmos1...") + if err != nil { + return err + } + + // Create a connection to the gRPC server. + grpcConn := grpc.Dial( + "127.0.0.1:9090", // Or your gRPC server address. + grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. + ) + defer grpcConn.Close() + + // This creates a gRPC client to query the x/bank service. + bankClient := banktypes.NewQueryClient(grpcConn) + bankRes, err := bankClient.Balance( + context.Background(), + &banktypes.QueryBalanceRequest{Address: myAddress, Denom: "atom"}, + ) + if err != nil { + return err + } + + fmt.Println(bankRes.GetBalance()) // Prints the account balance + + return nil } - -fmt.Println(bankRes.GetBalance()) // Prints the account balance ``` You can replace the query client (here we are using `x/bank`'s) with one generated from any other Protobuf service. The list of all available gRPC query endpoints is [coming soon](https://github.com/cosmos/cosmos-sdk/issues/7786). diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 0ac96c64f19d..0c4c9de47ccf 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -97,12 +97,16 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" ) -// Choose your codec: Amino or Protobuf. Here, we use Protobuf, given by the -// following function. -encCfg := simapp.MakeTestEncodingConfig() +func sendTx() error { + // Choose your codec: Amino or Protobuf. Here, we use Protobuf, given by the + // following function. + encCfg := simapp.MakeTestEncodingConfig() -// Create a new TxBuilder. -txBuilder := encCfg.TxConfig.NewTxBuilder() + // Create a new TxBuilder. + txBuilder := encCfg.TxConfig.NewTxBuilder() + + // --snip-- +} ``` We can also set up some keys and addresses that will send and receive the transactions. Here, for the purpose of the tutorial, we will be using some dummy data to create keys. @@ -124,22 +128,26 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -// Define two x/bank MsgSend messages: -// - from addr1 to addr3, -// - from addr2 to addr3. -// This means that the transactions needs two signers: addr1 and addr2. -msg1 := banktypes.NewMsgSend(addr1, addr3, types.NewCoins(types.NewInt64Coin("atom", 12))) -msg2 := banktypes.NewMsgSend(addr2, addr3, types.NewCoins(types.NewInt64Coin("atom", 34))) +func sendTx() error { + // --snip-- -err := txBuilder.SetMsgs(msg1, msg2) -if err != nil { - return err -} + // Define two x/bank MsgSend messages: + // - from addr1 to addr3, + // - from addr2 to addr3. + // This means that the transactions needs two signers: addr1 and addr2. + msg1 := banktypes.NewMsgSend(addr1, addr3, types.NewCoins(types.NewInt64Coin("atom", 12))) + msg2 := banktypes.NewMsgSend(addr2, addr3, types.NewCoins(types.NewInt64Coin("atom", 34))) + + err := txBuilder.SetMsgs(msg1, msg2) + if err != nil { + return err + } -txBuilder.SetGasLimit(...) -txBuilder.SetFeeAmount(...) -txBuilder.SetMemo(...) -txBuilder.SetTimeoutHeight(...) + txBuilder.SetGasLimit(...) + txBuilder.SetFeeAmount(...) + txBuilder.SetMemo(...) + txBuilder.SetTimeoutHeight(...) +} ``` At this point, `TxBuilder`'s underlying transaction is ready to be signed. @@ -160,68 +168,76 @@ import ( xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) -privs := []cryptotypes.PrivKey{priv1, priv2} -accNums:= []uint64{..., ...} // The accounts' account numbers -accSeqs:= []uint64{..., ...} // The accounts' sequence numbers - -// First round: we gather all the signer infos. We use the "set empty -// signature" hack to do that. -var sigsV2 []signing.SignatureV2 -for i, priv := range privs { - sigV2 := signing.SignatureV2{ - PubKey: priv.PubKey(), - Data: &signing.SingleSignatureData{ - SignMode: encCfg.TxConfig.SignModeHandler().DefaultMode(), - Signature: nil, - }, - Sequence: accSeqs[i], +func sendTx() error { + // --snip-- + + privs := []cryptotypes.PrivKey{priv1, priv2} + accNums:= []uint64{..., ...} // The accounts' account numbers + accSeqs:= []uint64{..., ...} // The accounts' sequence numbers + + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + var sigsV2 []signing.SignatureV2 + for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: encCfg.TxConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) + } + err := txBuilder.SetSignatures(sigsV2...) + if err != nil { + return err } - sigsV2 = append(sigsV2, sigV2) -} -err := txBuilder.SetSignatures(sigsV2...) -if err != nil { - return err -} - -// Second round: all signer infos are set, so each signer can sign. -sigsV2 = []signing.SignatureV2{} -for i, priv := range privs { - signerData := xauthsigning.SignerData{ - ChainID: chainID, - AccountNumber: accNums[i], - Sequence: accSeqs[i], + // Second round: all signer infos are set, so each signer can sign. + sigsV2 = []signing.SignatureV2{} + for i, priv := range privs { + signerData := xauthsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + sigV2, err := tx.SignWithPrivKey( + encCfg.TxConfig.SignModeHandler().DefaultMode(), signerData, + txBuilder, priv, encCfg.TxConfig, accSeqs[i]) + if err != nil { + return nil, err + } + + sigsV2 = append(sigsV2, sigV2) } - sigV2, err := tx.SignWithPrivKey( - encCfg.TxConfig.SignModeHandler().DefaultMode(), signerData, - txBuilder, priv, encCfg.TxConfig, accSeqs[i]) + err = txBuilder.SetSignatures(sigsV2...) if err != nil { - return nil, err + return err } - - sigsV2 = append(sigsV2, sigV2) -} -err = txBuilder.SetSignatures(sigsV2...) -if err != nil { - return err } ``` The `TxBuilder` is now correctly populated. To print it, you can use the `TxConfig` interface from the initial encoding config `encCfg`: ```go -// Generated Protobuf-encoded bytes. -txBytes, err := encCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) -if err != nil { - return err -} +func sendTx() error { + // --snip-- -// Generate a JSON string. -txJSONBytes, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) -if err != nil { - return err + // Generated Protobuf-encoded bytes. + txBytes, err := encCfg.TxConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return err + } + + // Generate a JSON string. + txJSONBytes, err := encCfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) + if err != nil { + return err + } + txJSON := string(txJSONBytes) } -txJSON := string(txJSONBytes) ``` ### Broadcasting a Transaction @@ -238,29 +254,35 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" ) -// Create a connection to the gRPC server. -grpcConn := grpc.Dial( - "127.0.0.1:9090", // Or your gRPC server address. - grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. -) -defer grpcConn.Close() - -// Broadcast the tx via gRPC. We create a new client for the Protobuf Tx -// service. -txClient := tx.NewServiceClient(grpcConn) -// We then call the BroadcastTx method on this client. -grpcRes, err := txClient.BroadcastTx( - context.Background(), - &tx.BroadcastTxRequest{ - Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, - TxBytes: txBytes, // Proto-binary of the signed transaction, see previous step. - }, -) -if err != nil { - return err -} +func sendTx() error { + // --snip-- + + // Create a connection to the gRPC server. + grpcConn := grpc.Dial( + "127.0.0.1:9090", // Or your gRPC server address. + grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism. + ) + defer grpcConn.Close() + + // Broadcast the tx via gRPC. We create a new client for the Protobuf Tx + // service. + txClient := tx.NewServiceClient(grpcConn) + // We then call the BroadcastTx method on this client. + grpcRes, err := txClient.BroadcastTx( + context.Background(), + &tx.BroadcastTxRequest{ + Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, + TxBytes: txBytes, // Proto-binary of the signed transaction, see previous step. + }, + ) + if err != nil { + return err + } + + fmt.Println(grpcRes.TxResponse.Code) // Should be `0` if the tx is successful -fmt.Println(grpcRes.TxResponse.Code) // Should be `0` if the tx is successful + return nil +} ``` #### Simulating a Transaction @@ -278,25 +300,31 @@ import ( authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" ) -// Simulate the tx via gRPC. We create a new client for the Protobuf Tx -// service. -txClient := tx.NewServiceClient(grpcConn) -// We then call the BroadcastTx method on this client. -protoTx := txBuilderToProtoTx(txBuilder) -if err != nil { - return err -} -grpcRes, err := txClient.Simulate( - context.Background(), - &tx.SimulateRequest{ - Tx: protoTx, - }, -) -if err != nil { - return err -} +func simulateTx() error { + // --snip-- + + // Simulate the tx via gRPC. We create a new client for the Protobuf Tx + // service. + txClient := tx.NewServiceClient(grpcConn) + // We then call the BroadcastTx method on this client. + protoTx := txBuilderToProtoTx(txBuilder) + if err != nil { + return err + } + grpcRes, err := txClient.Simulate( + context.Background(), + &tx.SimulateRequest{ + Tx: protoTx, + }, + ) + if err != nil { + return err + } -fmt.Println(grpcRes.GasInfo) // Prints estimated gas used. + fmt.Println(grpcRes.GasInfo) // Prints estimated gas used. + + return nil +} // txBuilderToProtoTx converts a txBuilder into a proto tx.Tx. func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint From dc10b7e5daa0148c80190d5372ff2d0768cc7f73 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 7 Jan 2021 17:18:17 +0100 Subject: [PATCH 11/11] Put snippet in functions --- docs/run-node/interact-node.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/run-node/interact-node.md b/docs/run-node/interact-node.md index 230d10baf232..60ce6c2ed591 100644 --- a/docs/run-node/interact-node.md +++ b/docs/run-node/interact-node.md @@ -178,18 +178,24 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx" ) -var header metadata.MD -bankRes, err = bankClient.Balance( - metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, "12"), // Add metadata to request - &banktypes.QueryBalanceRequest{Address: myAddress, Denom: denom}, - grpc.Header(&header), // Retrieve header from response -) -if err != nil { - return err -} -blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader) +func queryState() error { + // --snip-- -fmt.Println(blockHeight) // Prints the block height (12) + var header metadata.MD + bankRes, err = bankClient.Balance( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, "12"), // Add metadata to request + &banktypes.QueryBalanceRequest{Address: myAddress, Denom: denom}, + grpc.Header(&header), // Retrieve header from response + ) + if err != nil { + return err + } + blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader) + + fmt.Println(blockHeight) // Prints the block height (12) + + return nil +} ``` ### CosmJS