-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: Update transaction building using v2 #23257
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -207,3 +207,193 @@ An example can be seen [here](https://docs.cosmos.network/main/user/run-node/txs | |||||||||||||||||||||||||||||||||||||||
#### CometBFT RPC | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
The three methods presented above are actually higher abstractions over the CometBFT RPC `/broadcast_tx_{async,sync,commit}` endpoints, documented [here](https://docs.cometbft.com/v1.0/explanation/core/rpc). This means that you can use the CometBFT RPC endpoints directly to broadcast the transaction, if you wish so. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
#### Complete Example Building and Broadcasting a Transaction using clientv2 | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
1. Correctly set up imports | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||||||||||
"context" | ||||||||||||||||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||||||||||||||||
"log" | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
"google.golang.org/grpc" | ||||||||||||||||||||||||||||||||||||||||
"google.golang.org/grpc/credentials/insecure" | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
apisigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1" | ||||||||||||||||||||||||||||||||||||||||
"cosmossdk.io/client/v2/broadcast/comet" | ||||||||||||||||||||||||||||||||||||||||
"cosmossdk.io/client/v2/tx" | ||||||||||||||||||||||||||||||||||||||||
"cosmossdk.io/core/transaction" | ||||||||||||||||||||||||||||||||||||||||
"cosmossdk.io/math" | ||||||||||||||||||||||||||||||||||||||||
banktypes "cosmossdk.io/x/bank/types" | ||||||||||||||||||||||||||||||||||||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||||||||||||||||||||||||||||||||||||||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" | ||||||||||||||||||||||||||||||||||||||||
"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||||||||||||||||||||||||||||||||||||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
"github.com/cosmos/cosmos-sdk/codec" | ||||||||||||||||||||||||||||||||||||||||
addrcodec "github.com/cosmos/cosmos-sdk/codec/address" | ||||||||||||||||||||||||||||||||||||||||
sdk "github.com/cosmos/cosmos-sdk/types" | ||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
2. Create a gRPC connection | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
clientConn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials())) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal(err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+246
to
+250
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve security and configuration handling
+// Define configuration variables
+const (
+ defaultGRPCEndpoint = "127.0.0.1:9090"
+)
-clientConn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
+// TODO: In production, use secure credentials
+endpoint := os.Getenv("GRPC_ENDPOINT")
+if endpoint == "" {
+ endpoint = defaultGRPCEndpoint
+}
+clientConn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
3. Setup codec and interface registry | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
// Setup interface registry and register necessary interfaces | ||||||||||||||||||||||||||||||||||||||||
interfaceRegistry := codectypes.NewInterfaceRegistry() | ||||||||||||||||||||||||||||||||||||||||
banktypes.RegisterInterfaces(interfaceRegistry) | ||||||||||||||||||||||||||||||||||||||||
authtypes.RegisterInterfaces(interfaceRegistry) | ||||||||||||||||||||||||||||||||||||||||
cryptocodec.RegisterInterfaces(interfaceRegistry) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Create a ProtoCodec for encoding/decoding | ||||||||||||||||||||||||||||||||||||||||
protoCodec := codec.NewProtoCodec(interfaceRegistry) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
4. Initialize keyring | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
ckr, err := keyring.New("autoclikeyring", "test", home, nil, protoCodec) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error creating keyring", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
kr, err := keyring.NewAutoCLIKeyring(ckr, addrcodec.NewBech32Codec("cosmos")) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error creating auto cli keyring", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
5. Setup transaction parameters | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Setup transaction parameters | ||||||||||||||||||||||||||||||||||||||||
txParams := tx.TxParameters{ | ||||||||||||||||||||||||||||||||||||||||
ChainID: "simapp-v2-chain", | ||||||||||||||||||||||||||||||||||||||||
SignMode: apisigning.SignMode_SIGN_MODE_DIRECT, | ||||||||||||||||||||||||||||||||||||||||
AccountConfig: tx.AccountConfig{ | ||||||||||||||||||||||||||||||||||||||||
FromAddress: "cosmos1t0fmn0lyp2v99ga55mm37mpnqrlnc4xcs2hhhy", | ||||||||||||||||||||||||||||||||||||||||
FromName: "alice", | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Configure gas settings | ||||||||||||||||||||||||||||||||||||||||
gasConfig, err := tx.NewGasConfig(100, 100, "0stake") | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error creating gas config: ", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
txParams.GasConfig = gasConfig | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Create auth query client | ||||||||||||||||||||||||||||||||||||||||
authClient := authtypes.NewQueryClient(clientConn) | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Retrieve account information for the sender | ||||||||||||||||||||||||||||||||||||||||
fromAccount, err := getAccount("cosmos1t0fmn0lyp2v99ga55mm37mpnqrlnc4xcs2hhhy", authClient, protoCodec) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error getting from account: ", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Update txParams with the correct account number and sequence | ||||||||||||||||||||||||||||||||||||||||
txParams.AccountConfig.AccountNumber = fromAccount.GetAccountNumber() | ||||||||||||||||||||||||||||||||||||||||
txParams.AccountConfig.Sequence = fromAccount.GetSequence() | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Retrieve account information for the recipient | ||||||||||||||||||||||||||||||||||||||||
toAccount, err := getAccount("cosmos1e2wanzh89mlwct7cs7eumxf7mrh5m3ykpsh66m", authClient, protoCodec) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error getting to account: ", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Configure transaction settings | ||||||||||||||||||||||||||||||||||||||||
txConf, _ := tx.NewTxConfig(tx.ConfigOptions{ | ||||||||||||||||||||||||||||||||||||||||
AddressCodec: addrcodec.NewBech32Codec("cosmos"), | ||||||||||||||||||||||||||||||||||||||||
Cdc: protoCodec, | ||||||||||||||||||||||||||||||||||||||||
ValidatorAddressCodec: addrcodec.NewBech32Codec("cosmosval"), | ||||||||||||||||||||||||||||||||||||||||
EnabledSignModes: []apisigning.SignMode{apisigning.SignMode_SIGN_MODE_DIRECT}, | ||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
6. Build the transaction | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
// Create a transaction factory | ||||||||||||||||||||||||||||||||||||||||
f, err := tx.NewFactory(kr, codec.NewProtoCodec(codectypes.NewInterfaceRegistry()), nil, txConf, addrcodec.NewBech32Codec("cosmos"), clientConn, txParams) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error creating factory", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Define the transaction message | ||||||||||||||||||||||||||||||||||||||||
msgs := []transaction.Msg{ | ||||||||||||||||||||||||||||||||||||||||
&banktypes.MsgSend{ | ||||||||||||||||||||||||||||||||||||||||
FromAddress: fromAccount.GetAddress().String(), | ||||||||||||||||||||||||||||||||||||||||
ToAddress: toAccount.GetAddress().String(), | ||||||||||||||||||||||||||||||||||||||||
Amount: sdk.Coins{ | ||||||||||||||||||||||||||||||||||||||||
sdk.NewCoin("stake", math.NewInt(1000000)), | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Build and sign the transaction | ||||||||||||||||||||||||||||||||||||||||
tx, err := f.BuildsSignedTx(context.Background(), msgs...) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error building signed tx", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
7. Broadcast the transaction | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
// Create a broadcaster for the transaction | ||||||||||||||||||||||||||||||||||||||||
c, err := comet.NewCometBFTBroadcaster("http://127.0.0.1:26675", comet.BroadcastSync, protoCodec) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error creating comet broadcaster", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Broadcast the transaction | ||||||||||||||||||||||||||||||||||||||||
res, err := c.Broadcast(context.Background(), tx.Bytes()) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
log.Fatal("error broadcasting tx", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
8. Helpers | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```go | ||||||||||||||||||||||||||||||||||||||||
// getAccount retrieves account information using the provided address | ||||||||||||||||||||||||||||||||||||||||
func getAccount(address string, authClient authtypes.QueryClient, codec codec.Codec) (sdk.AccountI, error) { | ||||||||||||||||||||||||||||||||||||||||
// Query account info | ||||||||||||||||||||||||||||||||||||||||
accountQuery, err := authClient.Account(context.Background(), &authtypes.QueryAccountRequest{ | ||||||||||||||||||||||||||||||||||||||||
Address: string(address), | ||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("error getting account: %w", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// Unpack the account information | ||||||||||||||||||||||||||||||||||||||||
var account sdk.AccountI | ||||||||||||||||||||||||||||||||||||||||
err = codec.InterfaceRegistry().UnpackAny(accountQuery.Account, &account) | ||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("error unpacking account: %w", err) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
return account, nil | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, this should be moved under https://docs.cosmos.network/v0.52/tutorials and not here.
This page is about the general concepts of transactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what other think, but adding it here: https://github.com/cosmos/cosmos-sdk-docs/tree/main/docs/tutorials and maybe linking it in this page, makes more sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok , need write access here: https://github.com/cosmos/cosmos-sdk-docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can just fork it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the PR: cosmos/cosmos-sdk-docs#256
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks!