Skip to content

Commit

Permalink
Merge branch 'master' into bez/9393-bank-query-balance-holders
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez committed Jun 28, 2021
2 parents 5f944d6 + e17be87 commit 82a9488
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 148 deletions.
8 changes: 8 additions & 0 deletions .mergify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ pull_request_rules:
method: squash
strict: true
commit_message: title+body
- name: backport patches to v0.43.x branch
conditions:
- base=master
- label=backport/0.43.x
actions:
backport:
branches:
- release/v0.43.x
- name: backport patches to v0.42.x branch
conditions:
- base=master
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ Ref: https://keepachangelog.com/en/1.0.0/

* [\#9533](https://github.com/cosmos/cosmos-sdk/pull/9533) Added a new gRPC method, `DenomOwners`, in `x/bank` to query for all account holders of a specific denomination.

### API Breaking Changes

* (client/tx) [\#9421](https://github.com/cosmos/cosmos-sdk/pull/9421/) `BuildUnsignedTx`, `BuildSimTx`, `PrintUnsignedStdTx` functions are moved to
the Tx Factory as methods.

## [v0.43.0-rc0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.43.0-rc0) - 2021-06-25

### Features
Expand Down Expand Up @@ -115,7 +120,6 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (codec) [\#9251](https://github.com/cosmos/cosmos-sdk/pull/9251) Rename `clientCtx.JSONMarshaler` to `clientCtx.JSONCodec` as per #9226.
* (x/bank) [\#9271](https://github.com/cosmos/cosmos-sdk/pull/9271) SendEnabledCoin(s) renamed to IsSendEnabledCoin(s) to better reflect its functionality.


### State Machine Breaking

* (x/{bank,distrib,gov,slashing,staking}) [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Store keys have been modified to allow for variable-length addresses.
Expand Down
134 changes: 134 additions & 0 deletions client/tx/factory.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package tx

import (
"errors"
"fmt"
"os"

"github.com/spf13/pflag"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)
Expand Down Expand Up @@ -189,3 +194,132 @@ func (f Factory) WithTimeoutHeight(height uint64) Factory {
f.timeoutHeight = height
return f
}

// BuildUnsignedTx builds a transaction to be signed given a set of messages.
// Once created, the fee, memo, and messages are set.
func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
if f.chainID == "" {
return nil, fmt.Errorf("chain ID required but not specified")
}

fees := f.fees

if !f.gasPrices.IsZero() {
if !fees.IsZero() {
return nil, errors.New("cannot provide both fees and gas prices")
}

glDec := sdk.NewDec(int64(f.gas))

// Derive the fees based on the provided gas prices, where
// fee = ceil(gasPrice * gasLimit).
fees = make(sdk.Coins, len(f.gasPrices))

for i, gp := range f.gasPrices {
fee := gp.Amount.Mul(glDec)
fees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}
}

tx := f.txConfig.NewTxBuilder()

if err := tx.SetMsgs(msgs...); err != nil {
return nil, err
}

tx.SetMemo(f.memo)
tx.SetFeeAmount(fees)
tx.SetGasLimit(f.gas)
tx.SetTimeoutHeight(f.TimeoutHeight())

return tx, nil
}

// PrintUnsignedTx will generate an unsigned transaction and print it to the writer
// specified by ctx.Output. If simulation was requested, the gas will be
// simulated and also printed to the same writer before the transaction is
// printed.
func (f Factory) PrintUnsignedTx(clientCtx client.Context, msgs ...sdk.Msg) error {
if f.SimulateAndExecute() {
if clientCtx.Offline {
return errors.New("cannot estimate gas in offline mode")
}

_, adjusted, err := CalculateGas(clientCtx, f, msgs...)
if err != nil {
return err
}

f = f.WithGas(adjusted)
_, _ = fmt.Fprintf(os.Stderr, "%s\n", GasEstimateResponse{GasEstimate: f.Gas()})
}

tx, err := f.BuildUnsignedTx(msgs...)
if err != nil {
return err
}

json, err := clientCtx.TxConfig.TxJSONEncoder()(tx.GetTx())
if err != nil {
return err
}

return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
}

// BuildSimTx creates an unsigned tx with an empty single signature and returns
// the encoded transaction or an error if the unsigned transaction cannot be
// built.
func (f Factory) BuildSimTx(msgs ...sdk.Msg) ([]byte, error) {
txb, err := f.BuildUnsignedTx(msgs...)
if err != nil {
return nil, err
}

// Create an empty signature literal as the ante handler will populate with a
// sentinel pubkey.
sig := signing.SignatureV2{
PubKey: &secp256k1.PubKey{},
Data: &signing.SingleSignatureData{
SignMode: f.signMode,
},
Sequence: f.Sequence(),
}
if err := txb.SetSignatures(sig); err != nil {
return nil, err
}

return f.txConfig.TxEncoder()(txb.GetTx())
}

// Prepare ensures the account defined by ctx.GetFromAddress() exists and
// if the account number and/or the account sequence number are zero (not set),
// they will be queried for and set on the provided Factory. A new Factory with
// the updated fields will be returned.
func (f Factory) Prepare(clientCtx client.Context) (Factory, error) {
fc := f

from := clientCtx.GetFromAddress()

if err := fc.accountRetriever.EnsureExists(clientCtx, from); err != nil {
return fc, err
}

initNum, initSeq := fc.accountNumber, fc.sequence
if initNum == 0 || initSeq == 0 {
num, seq, err := fc.accountRetriever.GetAccountNumberSequence(clientCtx, from)
if err != nil {
return fc, err
}

if initNum == 0 {
fc = fc.WithAccountNumber(num)
}

if initSeq == 0 {
fc = fc.WithSequence(seq)
}
}

return fc, nil
}
139 changes: 5 additions & 134 deletions client/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -45,49 +44,17 @@ func GenerateOrBroadcastTxWithFactory(clientCtx client.Context, txf Factory, msg
}

if clientCtx.GenerateOnly {
return GenerateTx(clientCtx, txf, msgs...)
return txf.PrintUnsignedTx(clientCtx, msgs...)
}

return BroadcastTx(clientCtx, txf, msgs...)
}

// GenerateTx will generate an unsigned transaction and print it to the writer
// specified by ctx.Output. If simulation was requested, the gas will be
// simulated and also printed to the same writer before the transaction is
// printed.
func GenerateTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error {
if txf.SimulateAndExecute() {
if clientCtx.Offline {
return errors.New("cannot estimate gas in offline mode")
}

_, adjusted, err := CalculateGas(clientCtx, txf, msgs...)
if err != nil {
return err
}

txf = txf.WithGas(adjusted)
_, _ = fmt.Fprintf(os.Stderr, "%s\n", GasEstimateResponse{GasEstimate: txf.Gas()})
}

tx, err := BuildUnsignedTx(txf, msgs...)
if err != nil {
return err
}

json, err := clientCtx.TxConfig.TxJSONEncoder()(tx.GetTx())
if err != nil {
return err
}

return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
}

// BroadcastTx attempts to generate, sign and broadcast a transaction with the
// given set of messages. It will also simulate gas requirements if necessary.
// It will return an error upon failure.
func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error {
txf, err := prepareFactory(clientCtx, txf)
txf, err := txf.Prepare(clientCtx)
if err != nil {
return err
}
Expand All @@ -106,7 +73,7 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error {
return nil
}

tx, err := BuildUnsignedTx(txf, msgs...)
tx, err := txf.BuildUnsignedTx(msgs...)
if err != nil {
return err
}
Expand Down Expand Up @@ -197,7 +164,7 @@ func WriteGeneratedTxResponse(
}
}

tx, err := BuildUnsignedTx(txf, msgs...)
tx, err := txf.BuildUnsignedTx(msgs...)
if rest.CheckBadRequestError(w, err) {
return
}
Expand All @@ -217,78 +184,12 @@ func WriteGeneratedTxResponse(
_, _ = w.Write(output)
}

// BuildUnsignedTx builds a transaction to be signed given a set of messages. The
// transaction is initially created via the provided factory's generator. Once
// created, the fee, memo, and messages are set.
func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (client.TxBuilder, error) {
if txf.chainID == "" {
return nil, fmt.Errorf("chain ID required but not specified")
}

fees := txf.fees

if !txf.gasPrices.IsZero() {
if !fees.IsZero() {
return nil, errors.New("cannot provide both fees and gas prices")
}

glDec := sdk.NewDec(int64(txf.gas))

// Derive the fees based on the provided gas prices, where
// fee = ceil(gasPrice * gasLimit).
fees = make(sdk.Coins, len(txf.gasPrices))

for i, gp := range txf.gasPrices {
fee := gp.Amount.Mul(glDec)
fees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}
}

tx := txf.txConfig.NewTxBuilder()

if err := tx.SetMsgs(msgs...); err != nil {
return nil, err
}

tx.SetMemo(txf.memo)
tx.SetFeeAmount(fees)
tx.SetGasLimit(txf.gas)
tx.SetTimeoutHeight(txf.TimeoutHeight())

return tx, nil
}

// BuildSimTx creates an unsigned tx with an empty single signature and returns
// the encoded transaction or an error if the unsigned transaction cannot be
// built.
func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) {
txb, err := BuildUnsignedTx(txf, msgs...)
if err != nil {
return nil, err
}

// Create an empty signature literal as the ante handler will populate with a
// sentinel pubkey.
sig := signing.SignatureV2{
PubKey: &secp256k1.PubKey{},
Data: &signing.SingleSignatureData{
SignMode: txf.signMode,
},
Sequence: txf.Sequence(),
}
if err := txb.SetSignatures(sig); err != nil {
return nil, err
}

return txf.txConfig.TxEncoder()(txb.GetTx())
}

// CalculateGas simulates the execution of a transaction and returns the
// simulation response obtained by the query and the adjusted gas amount.
func CalculateGas(
clientCtx gogogrpc.ClientConn, txf Factory, msgs ...sdk.Msg,
) (*tx.SimulateResponse, uint64, error) {
txBytes, err := BuildSimTx(txf, msgs...)
txBytes, err := txf.BuildSimTx(msgs...)
if err != nil {
return nil, 0, err
}
Expand All @@ -304,36 +205,6 @@ func CalculateGas(
return simRes, uint64(txf.GasAdjustment() * float64(simRes.GasInfo.GasUsed)), nil
}

// prepareFactory ensures the account defined by ctx.GetFromAddress() exists and
// if the account number and/or the account sequence number are zero (not set),
// they will be queried for and set on the provided Factory. A new Factory with
// the updated fields will be returned.
func prepareFactory(clientCtx client.Context, txf Factory) (Factory, error) {
from := clientCtx.GetFromAddress()

if err := txf.accountRetriever.EnsureExists(clientCtx, from); err != nil {
return txf, err
}

initNum, initSeq := txf.accountNumber, txf.sequence
if initNum == 0 || initSeq == 0 {
num, seq, err := txf.accountRetriever.GetAccountNumberSequence(clientCtx, from)
if err != nil {
return txf, err
}

if initNum == 0 {
txf = txf.WithAccountNumber(num)
}

if initSeq == 0 {
txf = txf.WithSequence(seq)
}
}

return txf, nil
}

// SignWithPrivKey signs a given tx with the given private key, and returns the
// corresponding SignatureV2 if the signing is successful.
func SignWithPrivKey(
Expand Down
Loading

0 comments on commit 82a9488

Please sign in to comment.