Decouple client/tx from x/auth (#5992)

As part of #5864 part 2), this PR decouples the new client/tx
package from x/auth (as an incremental step to deprecating
all the tx logic in x/auth) and adds StdFee, StdSignature,
StdSignMsgBase and StdTxBase to codec/std, while
deprecating the corresponding types in x/auth.
This commit is contained in:
Aaron Craelius 2020-04-15 17:55:02 -04:00 committed by GitHub
parent aeee097b2f
commit bb4642ad0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1470 additions and 1353 deletions

View File

@ -9,6 +9,7 @@ import (
"strings"
"github.com/gogo/protobuf/jsonpb"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
@ -16,9 +17,8 @@ import (
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
type (
@ -27,6 +27,20 @@ type (
// implement ClientTx.
Generator interface {
NewTx() ClientTx
NewFee() ClientFee
NewSignature() ClientSignature
}
ClientFee interface {
sdk.Fee
SetGas(uint64)
SetAmount(sdk.Coins)
}
ClientSignature interface {
sdk.Signature
SetPubKey(crypto.PubKey) error
SetSignature([]byte)
}
// ClientTx defines an interface which an application-defined concrete transaction
@ -39,9 +53,9 @@ type (
SetMsgs(...sdk.Msg) error
GetSignatures() []sdk.Signature
SetSignatures(...sdk.Signature)
SetSignatures(...ClientSignature) error
GetFee() sdk.Fee
SetFee(sdk.Fee)
SetFee(ClientFee) error
GetMemo() string
SetMemo(string)
@ -176,7 +190,7 @@ func WriteGeneratedTxResponse(
if br.Simulate || simAndExec {
if gasAdj < 0 {
rest.WriteErrorResponse(w, http.StatusBadRequest, types.ErrorInvalidGasAdjustment.Error())
rest.WriteErrorResponse(w, http.StatusBadRequest, sdkerrors.ErrorInvalidGasAdjustment.Error())
return
}
@ -233,10 +247,20 @@ func BuildUnsignedTx(txf Factory, msgs ...sdk.Msg) (ClientTx, error) {
}
}
clientFee := txf.txGenerator.NewFee()
clientFee.SetAmount(fees)
clientFee.SetGas(txf.gas)
tx := txf.txGenerator.NewTx()
tx.SetFee(auth.NewStdFee(txf.gas, fees))
tx.SetMemo(txf.memo)
tx.SetSignatures()
if err := tx.SetFee(clientFee); err != nil {
return nil, err
}
if err := tx.SetSignatures(); err != nil {
return nil, err
}
if err := tx.SetMsgs(msgs...); err != nil {
return nil, err
@ -256,7 +280,11 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) {
// Create an empty signature literal as the ante handler will populate with a
// sentinel pubkey.
tx.SetSignatures(auth.NewStdSignature(nil, nil))
sig := txf.txGenerator.NewSignature()
if err := tx.SetSignatures(sig); err != nil {
return nil, err
}
return tx.Marshal()
}
@ -337,7 +365,17 @@ func Sign(txf Factory, name, passphrase string, tx ClientTx) ([]byte, error) {
return nil, err
}
tx.SetSignatures(auth.NewStdSignature(pubkey, sigBytes))
sig := txf.txGenerator.NewSignature()
sig.SetSignature(sigBytes)
if err := sig.SetPubKey(pubkey); err != nil {
return nil, err
}
if err := tx.SetSignatures(sig); err != nil {
return nil, err
}
return tx.Marshal()
}

View File

@ -10,7 +10,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/std"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
)
@ -87,7 +86,7 @@ func TestBuildSimTx(t *testing.T) {
tx := &std.Transaction{}
require.NoError(t, tx.Unmarshal(bz))
require.Equal(t, []sdk.Signature{sdk.Signature(auth.StdSignature{})}, tx.GetSignatures())
require.Equal(t, []sdk.Signature{sdk.Signature(std.StdSignature{})}, tx.GetSignatures())
}
func TestBuildUnsignedTx(t *testing.T) {

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ package cosmos_sdk.codec.std.v1;
import "third_party/proto/cosmos-proto/cosmos.proto";
import "third_party/proto/gogoproto/gogo.proto";
import "types/types.proto";
import "x/auth/types/types.proto";
import "x/auth/vesting/types/types.proto";
import "x/bank/types/types.proto";
@ -106,8 +107,7 @@ message Content {
message Transaction {
option (gogoproto.goproto_getters) = false;
cosmos_sdk.x.auth.v1.StdTxBase base = 1
[(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false];
StdTxBase base = 1 [(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false];
repeated Message msgs = 2 [(gogoproto.nullable) = false];
}
@ -141,7 +141,45 @@ message Message {
// SignDoc defines a standard application-level signing document to compose
// signatures for a Transaction.
message SignDoc {
cosmos_sdk.x.auth.v1.StdSignDocBase base = 1
[(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false];
StdSignDocBase base = 1 [(gogoproto.jsontag) = "", (gogoproto.embed) = true, (gogoproto.nullable) = false];
repeated Message msgs = 2 [(gogoproto.nullable) = false];
}
// StdFee includes the amount of coins paid in fees and the maximum
// gas to be used by the transaction. The ratio yields an effective "gasprice",
// which must be above some miminum to be accepted into the mempool.
message StdFee {
option (gogoproto.goproto_getters) = false;
option (gogoproto.equal) = true;
repeated cosmos_sdk.v1.Coin amount = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
uint64 gas = 2;
}
// StdSignature defines a signature structure that contains the signature of a
// transaction and an optional public key.
message StdSignature {
option (gogoproto.goproto_getters) = false;
bytes pub_key = 1 [(gogoproto.jsontag) = "public_key,omitempty", (gogoproto.moretags) = "yaml:\"public_key\""];
bytes signature = 2;
}
// StdTxBase defines a transaction base which application-level concrete transaction
// types can extend.
message StdTxBase {
StdFee fee = 1 [(gogoproto.nullable) = false];
repeated StdSignature signatures = 2 [(gogoproto.nullable) = false];
string memo = 3;
}
// StdSignDocBase defines the base structure for which applications can extend
// to define the concrete structure that signers sign over.
message StdSignDocBase {
string chain_id = 1 [(gogoproto.customname) = "ChainID", (gogoproto.moretags) = "yaml:\"chain_id\""];
uint64 account_number = 2 [(gogoproto.moretags) = "yaml:\"account_number\""];
uint64 sequence = 3;
string memo = 4;
StdFee fee = 5 [(gogoproto.nullable) = false];
}

View File

@ -1,6 +1,9 @@
package std
import (
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto"
clientx "github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@ -8,23 +11,33 @@ import (
)
var (
_ sdk.Tx = (*Transaction)(nil)
_ clientx.ClientTx = (*Transaction)(nil)
_ clientx.Generator = TxGenerator{}
_ sdk.Tx = (*Transaction)(nil)
_ clientx.ClientTx = (*Transaction)(nil)
_ clientx.Generator = TxGenerator{}
_ clientx.ClientFee = &StdFee{}
_ clientx.ClientSignature = &StdSignature{}
)
// TxGenerator defines a transaction generator that allows clients to construct
// transactions.
type TxGenerator struct{}
func (g TxGenerator) NewFee() clientx.ClientFee {
return &StdFee{}
}
func (g TxGenerator) NewSignature() clientx.ClientSignature {
return &StdSignature{}
}
// NewTx returns a reference to an empty Transaction type.
func (TxGenerator) NewTx() clientx.ClientTx {
return &Transaction{}
}
func NewTransaction(fee auth.StdFee, memo string, sdkMsgs []sdk.Msg) (*Transaction, error) {
func NewTransaction(fee StdFee, memo string, sdkMsgs []sdk.Msg) (*Transaction, error) {
tx := &Transaction{
StdTxBase: auth.NewStdTxBase(fee, nil, memo),
StdTxBase: NewStdTxBase(fee, nil, memo),
}
if err := tx.SetMsgs(sdkMsgs...); err != nil {
@ -121,15 +134,16 @@ func (tx Transaction) GetSignatures() []sdk.Signature {
// SetSignatures sets the transaction's signatures. It will overwrite any
// existing signatures set.
func (tx *Transaction) SetSignatures(sdkSigs ...sdk.Signature) {
sigs := make([]auth.StdSignature, len(sdkSigs))
func (tx *Transaction) SetSignatures(sdkSigs ...clientx.ClientSignature) error {
sigs := make([]StdSignature, len(sdkSigs))
for i, sig := range sdkSigs {
if sig != nil {
sigs[i] = auth.NewStdSignature(sig.GetPubKey(), sig.GetSignature())
sigs[i] = NewStdSignature(sig.GetPubKey(), sig.GetSignature())
}
}
tx.Signatures = sigs
return nil
}
// GetFee returns the transaction's fee.
@ -138,8 +152,9 @@ func (tx Transaction) GetFee() sdk.Fee {
}
// SetFee sets the transaction's fee. It will overwrite any existing fee set.
func (tx *Transaction) SetFee(fee sdk.Fee) {
tx.Fee = auth.NewStdFee(fee.GetGas(), fee.GetAmount())
func (tx *Transaction) SetFee(fee clientx.ClientFee) error {
tx.Fee = NewStdFee(fee.GetGas(), fee.GetAmount())
return nil
}
// GetMemo returns the transaction's memo.
@ -160,9 +175,9 @@ func (tx Transaction) CanonicalSignBytes(cid string, num, seq uint64) ([]byte, e
return NewSignDoc(num, seq, cid, tx.Memo, tx.Fee, tx.Msgs...).CanonicalSignBytes()
}
func NewSignDoc(num, seq uint64, cid, memo string, fee auth.StdFee, msgs ...Message) *SignDoc {
func NewSignDoc(num, seq uint64, cid, memo string, fee StdFee, msgs ...Message) *SignDoc {
return &SignDoc{
StdSignDocBase: auth.NewStdSignDocBase(num, seq, cid, memo, fee),
StdSignDocBase: NewStdSignDocBase(num, seq, cid, memo, fee),
Msgs: msgs,
}
}
@ -174,3 +189,77 @@ func NewSignDoc(num, seq uint64, cid, memo string, fee auth.StdFee, msgs ...Mess
func (sd *SignDoc) CanonicalSignBytes() ([]byte, error) {
return sdk.CanonicalSignBytes(sd)
}
// NewStdFee returns a new instance of StdFee
func NewStdFee(gas uint64, amount sdk.Coins) StdFee {
return StdFee{
Amount: amount,
Gas: gas,
}
}
func NewStdSignature(pk crypto.PubKey, sig []byte) StdSignature {
var pkBz []byte
if pk != nil {
pkBz = pk.Bytes()
}
return StdSignature{PubKey: pkBz, Signature: sig}
}
func NewStdTxBase(fee StdFee, sigs []StdSignature, memo string) StdTxBase {
return StdTxBase{
Fee: fee,
Signatures: sigs,
Memo: memo,
}
}
func NewStdSignDocBase(num, seq uint64, cid, memo string, fee StdFee) StdSignDocBase {
return StdSignDocBase{
ChainID: cid,
AccountNumber: num,
Sequence: seq,
Memo: memo,
Fee: fee,
}
}
func (m StdFee) GetGas() uint64 {
return m.Gas
}
func (m StdFee) GetAmount() sdk.Coins {
return m.Amount
}
func (m *StdFee) SetGas(gas uint64) {
m.Gas = gas
}
func (m *StdFee) SetAmount(amount sdk.Coins) {
m.Amount = amount
}
func (m StdSignature) GetPubKey() crypto.PubKey {
var pk crypto.PubKey
if len(m.PubKey) == 0 {
return nil
}
amino.MustUnmarshalBinaryBare(m.PubKey, &pk)
return pk
}
func (m StdSignature) GetSignature() []byte {
return m.Signature
}
func (m *StdSignature) SetPubKey(pk crypto.PubKey) error {
m.PubKey = pk.Bytes()
return nil
}
func (m *StdSignature) SetSignature(signature []byte) {
m.Signature = signature
}

View File

@ -7,12 +7,11 @@ import (
"github.com/cosmos/cosmos-sdk/codec/std"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
)
func TestTransaction(t *testing.T) {
f := auth.NewStdFee(100, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)))
f := std.NewStdFee(100, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)))
m := "hello world"
acc1 := sdk.AccAddress("from")
acc2 := sdk.AccAddress("to")

View File

@ -88,6 +88,12 @@ var (
// ErrWrongPassword defines an error when the key password is invalid.
ErrWrongPassword = Register(RootCodespace, 23, "invalid account password")
// ErrorInvalidSigner defines an error when the tx intended signer does not match the given signer.
ErrorInvalidSigner = Register(RootCodespace, 24, "tx intended signer does not match the given signer")
// ErrorInvalidGasAdjustment defines an error for an invalid gas adjustment
ErrorInvalidGasAdjustment = Register(RootCodespace, 25, "invalid gas adjustment")
// ErrPanic is only set when we recover from a panic, so we know to
// redact potentially sensitive system info
ErrPanic = Register(UndefinedCodespace, 111222, "panic")

View File

@ -60,8 +60,6 @@ var (
ValidateGenAccounts = types.ValidateGenAccounts
GetGenesisStateFromAppState = types.GetGenesisStateFromAppState
NewStdSignature = types.NewStdSignature
NewStdTxBase = types.NewStdTxBase
NewStdSignDocBase = types.NewStdSignDocBase
// variable aliases
ModuleCdc = types.ModuleCdc
@ -91,6 +89,4 @@ type (
TxBuilder = types.TxBuilder
GenesisAccountIterator = types.GenesisAccountIterator
Codec = types.Codec
StdSignDocBase = types.StdSignDocBase
StdTxBase = types.StdTxBase
)

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
@ -30,7 +31,7 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext
if br.Simulate || simAndExec {
if gasAdj < 0 {
rest.WriteErrorResponse(w, http.StatusBadRequest, types.ErrorInvalidGasAdjustment.Error())
rest.WriteErrorResponse(w, http.StatusBadRequest, errors.ErrorInvalidGasAdjustment.Error())
return
}

View File

@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
@ -193,7 +194,7 @@ func SignStdTx(
// check whether the address is a signer
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", authtypes.ErrorInvalidSigner, name)
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
}
if !offline {
@ -216,7 +217,7 @@ func SignStdTxWithSignerAddress(
// check whether the address is a signer
if !isTxSigner(addr, stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", authtypes.ErrorInvalidSigner, name)
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
}
if !offline {

View File

@ -1,10 +0,0 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
var (
ErrorInvalidSigner = sdkerrors.Register(ModuleName, 2, "tx intended signer does not match the given signer")
ErrorInvalidGasAdjustment = sdkerrors.Register(ModuleName, 3, "invalid gas adjustment")
)

View File

@ -17,7 +17,15 @@ import (
// MaxGasWanted defines the max gas allowed.
const MaxGasWanted = uint64((1 << 63) - 1)
// NewStdFee returns a new instance of StdFee
// Deprecated: StdFee includes the amount of coins paid in fees and the maximum
// gas to be used by the transaction. The ratio yields an effective "gasprice",
// which must be above some miminum to be accepted into the mempool.
type StdFee struct {
Amount sdk.Coins `json:"amount" yaml:"amount"`
Gas uint64 `json:"gas" yaml:"gas"`
}
// Deprecated: NewStdFee returns a new instance of StdFee
func NewStdFee(gas uint64, amount sdk.Coins) StdFee {
return StdFee{
Amount: amount,
@ -58,6 +66,7 @@ func (fee StdFee) GasPrices() sdk.DecCoins {
return sdk.NewDecCoinsFromCoins(fee.Amount...).QuoDec(sdk.NewDec(int64(fee.Gas)))
}
// Deprecated
func NewStdSignature(pk crypto.PubKey, sig []byte) StdSignature {
var pkBz []byte
if pk != nil {
@ -112,24 +121,6 @@ func (ss StdSignature) MarshalYAML() (interface{}, error) {
return string(bz), err
}
func NewStdTxBase(fee StdFee, sigs []StdSignature, memo string) StdTxBase {
return StdTxBase{
Fee: fee,
Signatures: sigs,
Memo: memo,
}
}
func NewStdSignDocBase(num, seq uint64, cid, memo string, fee StdFee) StdSignDocBase {
return StdSignDocBase{
ChainID: cid,
AccountNumber: num,
Sequence: seq,
Memo: memo,
Fee: fee,
}
}
// CountSubKeys counts the total number of keys for a multi-sig public key.
func CountSubKeys(pub crypto.PubKey) int {
v, ok := pub.(multisig.PubKeyMultisigThreshold)
@ -320,6 +311,12 @@ func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee StdFee, ms
return sdk.MustSortJSON(bz)
}
// Deprecated: StdSignature represents a sig
type StdSignature struct {
PubKey []byte `json:"pub_key" yaml:"pub_key"` // optional
Signature []byte `json:"signature" yaml:"signature"`
}
// DefaultTxDecoder logic for standard transaction decoding
func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, error) {

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@ syntax = "proto3";
package cosmos_sdk.x.auth.v1;
import "third_party/proto/gogoproto/gogo.proto";
import "types/types.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types";
@ -19,27 +18,6 @@ message BaseAccount {
uint64 sequence = 4;
}
// StdFee includes the amount of coins paid in fees and the maximum
// gas to be used by the transaction. The ratio yields an effective "gasprice",
// which must be above some miminum to be accepted into the mempool.
message StdFee {
option (gogoproto.goproto_getters) = false;
option (gogoproto.equal) = true;
repeated cosmos_sdk.v1.Coin amount = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
uint64 gas = 2;
}
// StdSignature defines a signature structure that contains the signature of a
// transaction and an optional public key.
message StdSignature {
option (gogoproto.goproto_getters) = false;
bytes pub_key = 1 [(gogoproto.jsontag) = "public_key,omitempty", (gogoproto.moretags) = "yaml:\"public_key\""];
bytes signature = 2;
}
// Params defines the parameters for the auth module.
message Params {
option (gogoproto.equal) = true;
@ -49,25 +27,8 @@ message Params {
uint64 tx_sig_limit = 2 [(gogoproto.moretags) = "yaml:\"tx_sig_limit\""];
uint64 tx_size_cost_per_byte = 3 [(gogoproto.moretags) = "yaml:\"tx_size_cost_per_byte\""];
uint64 sig_verify_cost_ed25519 = 4
[(gogoproto.customname) = "SigVerifyCostED25519", (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\""];
[(gogoproto.customname) = "SigVerifyCostED25519", (gogoproto.moretags) = "yaml:\"sig_verify_cost_ed25519\""];
uint64 sig_verify_cost_secp256k1 = 5
[(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""];
[(gogoproto.customname) = "SigVerifyCostSecp256k1", (gogoproto.moretags) = "yaml:\"sig_verify_cost_secp256k1\""];
}
// StdTxBase defines a transaction base which application-level concrete transaction
// types can extend.
message StdTxBase {
StdFee fee = 1 [(gogoproto.nullable) = false];
repeated StdSignature signatures = 2 [(gogoproto.nullable) = false];
string memo = 3;
}
// StdSignDocBase defines the base structure for which applications can extend
// to define the concrete structure that signers sign over.
message StdSignDocBase {
string chain_id = 1 [(gogoproto.customname) = "ChainID", (gogoproto.moretags) = "yaml:\"chain_id\""];
uint64 account_number = 2 [(gogoproto.moretags) = "yaml:\"account_number\""];
uint64 sequence = 3;
string memo = 4;
StdFee fee = 5 [(gogoproto.nullable) = false];
}