Update auth cli commands (#6717)

* add utils

* update sign cmd

* update multisign cmd

* update sign batch cmd

* update genutil cmd

* add wrap tx builder

* update gentx cli

* update validate sigs cmd

* fix lint

* add flag reader to cli

* update marshaler for batchscan

* add register query server

* update to master

* remove depricated methods

* fix keyring issue

* update wraptx

* Fix batch scan

* fix register interfaces issue

* update printOutput

* Update Validate Sigs test

* WIP on signature JSON

* Cleanup

* Cleanup

* Test fixes

* Test fixes

* Fixes

* WIP on tests

* Fix gov tests

* fix lint

* fix MultiSign tests

* fix tests

* refactor tests

* Cleanup

* Address review comments

* Update encode

* Test fix

* Rename SignData func

* Fix lint

* Fix lint

* Revert ReadTxCommandFlags

Co-authored-by: Aaron Craelius <aaron@regen.network>
Co-authored-by: Aaron Craelius <aaronc@users.noreply.github.com>
This commit is contained in:
SaReN 2020-07-30 04:03:42 +05:30 committed by GitHub
parent cf078c0c88
commit 72ebafeeca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1986 additions and 537 deletions

View File

@ -195,6 +195,17 @@ func (ctx Context) WithInterfaceRegistry(interfaceRegistry codectypes.InterfaceR
return ctx return ctx
} }
// PrintString prints the raw string to ctx.Output or os.Stdout
func (ctx Context) PrintString(str string) error {
writer := ctx.Output
if writer == nil {
writer = os.Stdout
}
_, err := writer.Write([]byte(str))
return err
}
// PrintOutput outputs toPrint to the ctx.Output based on ctx.OutputFormat which is // PrintOutput outputs toPrint to the ctx.Output based on ctx.OutputFormat which is
// either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint // either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint
// will be JSON encoded using ctx.JSONMarshaler. An error is returned upon failure. // will be JSON encoded using ctx.JSONMarshaler. An error is returned upon failure.

View File

@ -172,3 +172,14 @@ func (f Factory) WithSimulateAndExecute(sim bool) Factory {
f.simulateAndExecute = sim f.simulateAndExecute = sim
return f return f
} }
// SignMode returns the sign mode configured in the Factory
func (f Factory) SignMode() signing.SignMode {
return f.signMode
}
// WithSignMode returns a copy of the Factory with an updated sign mode value.
func (f Factory) WithSignMode(mode signing.SignMode) Factory {
f.signMode = mode
return f
}

View File

@ -64,7 +64,12 @@ func GenerateTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error {
return err return err
} }
return clientCtx.PrintOutput(tx.GetTx()) 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 // BroadcastTx attempts to generate, sign and broadcast a transaction with the

View File

@ -17,6 +17,8 @@ type (
TxDecoder() sdk.TxDecoder TxDecoder() sdk.TxDecoder
TxJSONEncoder() sdk.TxEncoder TxJSONEncoder() sdk.TxEncoder
TxJSONDecoder() sdk.TxDecoder TxJSONDecoder() sdk.TxDecoder
MarshalSignatureJSON([]signingtypes.SignatureV2) ([]byte, error)
UnmarshalSignatureJSON([]byte) ([]signingtypes.SignatureV2, error)
} }
// TxConfig defines an interface a client can utilize to generate an // TxConfig defines an interface a client can utilize to generate an

View File

@ -16,7 +16,9 @@ type ProtoCodec struct {
anyUnpacker types.AnyUnpacker anyUnpacker types.AnyUnpacker
} }
func NewProtoCodec(anyUnpacker types.AnyUnpacker) Marshaler { var _ Marshaler = &ProtoCodec{}
func NewProtoCodec(anyUnpacker types.AnyUnpacker) *ProtoCodec {
return &ProtoCodec{anyUnpacker: anyUnpacker} return &ProtoCodec{anyUnpacker: anyUnpacker}
} }

View File

@ -204,7 +204,7 @@ func mustAny(msg proto.Message) *types.Any {
} }
func BenchmarkProtoCodecMarshalBinaryLengthPrefixed(b *testing.B) { func BenchmarkProtoCodecMarshalBinaryLengthPrefixed(b *testing.B) {
var pCdc = codec.NewProtoCodec(types.NewInterfaceRegistry()).(*codec.ProtoCodec) var pCdc = codec.NewProtoCodec(types.NewInterfaceRegistry())
var msg = &testdata.HasAnimal{ var msg = &testdata.HasAnimal{
X: 1000, X: 1000,
Animal: mustAny(&testdata.HasAnimal{ Animal: mustAny(&testdata.HasAnimal{

View File

@ -17,6 +17,9 @@ type PubKey interface {
// GetPubKeys returns the crypto.PubKey's nested within the multi-sig PubKey // GetPubKeys returns the crypto.PubKey's nested within the multi-sig PubKey
GetPubKeys() []crypto.PubKey GetPubKeys() []crypto.PubKey
// GetThreshold returns the threshold number of signatures that must be obtained to verify a signature.
GetThreshold() uint
} }
// GetSignBytesFunc defines a function type which returns sign bytes for a given SignMode or an error. // GetSignBytesFunc defines a function type which returns sign bytes for a given SignMode or an error.

View File

@ -154,3 +154,8 @@ func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool {
} }
return true return true
} }
// GetThreshold implements the PubKey.GetThreshold method
func (pk PubKeyMultisigThreshold) GetThreshold() uint {
return pk.K
}

5
go.sum
View File

@ -168,8 +168,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -646,7 +644,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20u
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@ -772,7 +769,5 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@ -1,6 +1,8 @@
syntax = "proto3"; syntax = "proto3";
package cosmos.tx.signing; package cosmos.tx.signing;
import "cosmos/crypto/crypto.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types/tx/signing"; option go_package = "github.com/cosmos/cosmos-sdk/types/tx/signing";
// SignMode represents a signing mode with its own security guarantees // SignMode represents a signing mode with its own security guarantees
@ -20,3 +22,49 @@ enum SignMode {
// Amino JSON and will be removed in the future // Amino JSON and will be removed in the future
SIGN_MODE_LEGACY_AMINO_JSON = 127; SIGN_MODE_LEGACY_AMINO_JSON = 127;
} }
// SignatureDescriptors wraps multiple SignatureDescriptor's.
message SignatureDescriptors {
// signatures are the signature descriptors
repeated SignatureDescriptor signatures = 1;
}
// SignatureDescriptor is a convenience type which represents the full data for a
// signature including the public key of the signer, signing modes and the signature
// itself. It is primarily used for coordinating signatures between clients.
message SignatureDescriptor {
// public_key is the public key of the signer
cosmos.crypto.PublicKey public_key = 1;
Data data = 2;
// Data represents signature data
message Data {
// sum is the oneof that specifies whether this represents single or multi-signature data
oneof sum {
// single represents a single signer
Single single = 1;
// multi represents a multisig signer
Multi multi = 2;
}
// Single is the signature data for a single signer
message Single {
// mode is the signing mode of the single signer
cosmos.tx.signing.SignMode mode = 1;
// signature is the raw signature bytes
bytes signature = 2;
}
// Multi is the signature data for a multisig public key
message Multi {
// bitarray specifies which keys within the multisig are signing
cosmos.crypto.CompactBitArray bitarray = 1;
// signatures is the signatures of the multi-signature
repeated Data signatures = 2;
}
}
}

View File

@ -12,15 +12,15 @@ import (
// MakeEncodingConfig creates an EncodingConfig for an amino based test configuration. // MakeEncodingConfig creates an EncodingConfig for an amino based test configuration.
func MakeEncodingConfig() EncodingConfig { func MakeEncodingConfig() EncodingConfig {
cdc := codec.New() amino := codec.New()
interfaceRegistry := types.NewInterfaceRegistry() interfaceRegistry := types.NewInterfaceRegistry()
marshaler := codec.NewHybridCodec(cdc, interfaceRegistry) marshaler := codec.NewHybridCodec(amino, interfaceRegistry)
txGen := tx.NewTxConfig(interfaceRegistry, std.DefaultPublicKeyCodec{}, tx.DefaultSignModeHandler()) txGen := tx.NewTxConfig(codec.NewProtoCodec(interfaceRegistry), std.DefaultPublicKeyCodec{}, tx.DefaultSignModeHandler())
return EncodingConfig{ return EncodingConfig{
InterfaceRegistry: interfaceRegistry, InterfaceRegistry: interfaceRegistry,
Marshaler: marshaler, Marshaler: marshaler,
TxConfig: txGen, TxConfig: txGen,
Amino: cdc, Amino: amino,
} }
} }

View File

@ -13,8 +13,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
tmcfg "github.com/tendermint/tendermint/config" tmcfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
@ -29,6 +27,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys" clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"

37
types/tx/sig_desc.pb.go Normal file
View File

@ -0,0 +1,37 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/tx/sig_desc.proto
package tx
import (
fmt "fmt"
_ "github.com/cosmos/cosmos-sdk/types/tx/signing"
proto "github.com/gogo/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
func init() { proto.RegisterFile("cosmos/tx/sig_desc.proto", fileDescriptor_d560eb6bd3d62ef7) }
var fileDescriptor_d560eb6bd3d62ef7 = []byte{
// 129 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x48, 0xce, 0x2f, 0xce,
0xcd, 0x2f, 0xd6, 0x2f, 0xa9, 0xd0, 0x2f, 0xce, 0x4c, 0x8f, 0x4f, 0x49, 0x2d, 0x4e, 0xd6, 0x2b,
0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xc8, 0xe8, 0x95, 0x54, 0x48, 0xc9, 0xa3, 0x28, 0xca,
0xcb, 0xcc, 0x4b, 0x87, 0xd1, 0x10, 0xb5, 0x4e, 0xf6, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24,
0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78,
0x2c, 0xc7, 0x10, 0xa5, 0x9a, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f,
0x35, 0x05, 0x42, 0xe9, 0x16, 0xa7, 0x64, 0xeb, 0x97, 0x54, 0x16, 0xa4, 0x82, 0x8c, 0x4d, 0x62,
0x03, 0x9b, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x86, 0x8a, 0xa4, 0x8a, 0x8f, 0x00, 0x00,
0x00,
}

View File

@ -1,6 +1,10 @@
package signing package signing
import "github.com/tendermint/tendermint/crypto" import (
"fmt"
"github.com/tendermint/tendermint/crypto"
)
// SignatureV2 is a convenience type that is easier to use in application logic // SignatureV2 is a convenience type that is easier to use in application logic
// than the protobuf SignerInfo's and raw signature bytes. It goes beyond the // than the protobuf SignerInfo's and raw signature bytes. It goes beyond the
@ -15,3 +19,64 @@ type SignatureV2 struct {
// the signatures themselves for either single or multi-signatures. // the signatures themselves for either single or multi-signatures.
Data SignatureData Data SignatureData
} }
// SignatureDataToProto converts a SignatureData to SignatureDescriptor_Data.
// SignatureDescriptor_Data is considered an encoding type whereas SignatureData is used for
// business logic.
func SignatureDataToProto(data SignatureData) *SignatureDescriptor_Data {
switch data := data.(type) {
case *SingleSignatureData:
return &SignatureDescriptor_Data{
Sum: &SignatureDescriptor_Data_Single_{
Single: &SignatureDescriptor_Data_Single{
Mode: data.SignMode,
Signature: data.Signature,
},
},
}
case *MultiSignatureData:
descDatas := make([]*SignatureDescriptor_Data, len(data.Signatures))
for j, d := range data.Signatures {
descDatas[j] = SignatureDataToProto(d)
}
return &SignatureDescriptor_Data{
Sum: &SignatureDescriptor_Data_Multi_{
Multi: &SignatureDescriptor_Data_Multi{
Bitarray: data.BitArray,
Signatures: descDatas,
},
},
}
default:
panic(fmt.Errorf("unexpected case %+v", data))
}
}
// SignatureDataFromProto converts a SignatureDescriptor_Data to SignatureData.
// SignatureDescriptor_Data is considered an encoding type whereas SignatureData is used for
// business logic.
func SignatureDataFromProto(descData *SignatureDescriptor_Data) SignatureData {
switch descData := descData.Sum.(type) {
case *SignatureDescriptor_Data_Single_:
return &SingleSignatureData{
SignMode: descData.Single.Mode,
Signature: descData.Single.Signature,
}
case *SignatureDescriptor_Data_Multi_:
multi := descData.Multi
datas := make([]SignatureData, len(multi.Signatures))
for j, d := range multi.Signatures {
datas[j] = SignatureDataFromProto(d)
}
return &MultiSignatureData{
BitArray: multi.Bitarray,
Signatures: datas,
}
default:
panic(fmt.Errorf("unexpected case %+v", descData))
}
}

File diff suppressed because it is too large Load Diff

View File

@ -14,19 +14,16 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codec2 "github.com/cosmos/cosmos-sdk/codec" codec2 "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig" "github.com/cosmos/cosmos-sdk/crypto/types/multisig"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network" "github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil" authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
"github.com/cosmos/cosmos-sdk/x/auth/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
) )
@ -47,7 +44,21 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.cfg = cfg s.cfg = cfg
s.network = network.New(s.T(), cfg) s.network = network.New(s.T(), cfg)
_, err := s.network.WaitForHeight(1) kb := s.network.Validators[0].ClientCtx.Keyring
_, _, err := kb.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
account1, _, err := kb.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
_, err = kb.SaveMultisig("multi", multi)
s.Require().NoError(err)
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err) s.Require().NoError(err)
} }
@ -73,29 +84,23 @@ func (s *IntegrationTestSuite) TestCLIValidateSignatures() {
) )
s.Require().NoError(err) s.Require().NoError(err)
var tx types.StdTx
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &tx)
s.Require().NoError(err)
// write unsigned tx to file // write unsigned tx to file
unsignedTx, cleanup := testutil.WriteToNewTempFile(s.T(), res.String()) unsignedTx, cleanup := testutil.WriteToNewTempFile(s.T(), res.String())
defer cleanup() defer cleanup()
res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name())
s.Require().NoError(err) s.Require().NoError(err)
signedTx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(res.Bytes())
var signedTx types.StdTx
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &signedTx)
s.Require().NoError(err) s.Require().NoError(err)
signedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), res.String()) signedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), res.String())
defer cleanup() defer cleanup()
txBuilder, err := val.ClientCtx.TxConfig.WrapTxBuilder(signedTx)
res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name()) res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name())
s.Require().NoError(err) s.Require().NoError(err)
signedTx.Memo = "MODIFIED STD TX" txBuilder.SetMemo("MODIFIED TX")
bz, err := val.ClientCtx.JSONMarshaler.MarshalJSON(signedTx) bz, err := val.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
s.Require().NoError(err) s.Require().NoError(err)
modifiedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(bz)) modifiedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(bz))
@ -147,28 +152,26 @@ func (s *IntegrationTestSuite) TestCLISignBatch() {
defer cleanup2() defer cleanup2()
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID))
s.Require().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value") s.Require().Error(err)
// Sign batch malformed tx file signature only. // Sign batch malformed tx file signature only.
res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only")
s.Require().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value") s.Require().Error(err)
} }
func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
val1 := s.network.Validators[0] val1 := s.network.Validators[0]
account, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account, err := val1.ClientCtx.Keyring.Key("newAccount")
s.Require().NoError(err) s.Require().NoError(err)
sendTokens := sdk.TokensFromConsensusPower(10) sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
normalGeneratedTx, err := bankcli.MsgSendExec( normalGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
account.GetAddress(), account.GetAddress(),
sdk.NewCoins( sdk.NewCoins(sendTokens),
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -176,19 +179,22 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
) )
s.Require().NoError(err) s.Require().NoError(err)
normalGeneratedStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, normalGeneratedTx.String()) txCfg := val1.ClientCtx.TxConfig
s.Require().Equal(normalGeneratedStdTx.Fee.Gas, uint64(flags.DefaultGasLimit))
s.Require().Equal(len(normalGeneratedStdTx.Msgs), 1) normalGeneratedStdTx, err := txCfg.TxJSONDecoder()(normalGeneratedTx.Bytes())
s.Require().Equal(0, len(normalGeneratedStdTx.GetSignatures())) s.Require().NoError(err)
txBuilder, err := txCfg.WrapTxBuilder(normalGeneratedStdTx)
s.Require().NoError(err)
s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(flags.DefaultGasLimit))
s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
s.Require().Equal(0, len(txBuilder.GetTx().GetSignatures()))
// Test generate sendTx with --gas=$amount // Test generate sendTx with --gas=$amount
limitedGasGeneratedTx, err := bankcli.MsgSendExec( limitedGasGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
account.GetAddress(), account.GetAddress(),
sdk.NewCoins( sdk.NewCoins(sendTokens),
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -197,19 +203,28 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
) )
s.Require().NoError(err) s.Require().NoError(err)
limitedGasStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, limitedGasGeneratedTx.String()) limitedGasStdTx, err := txCfg.TxJSONDecoder()(limitedGasGeneratedTx.Bytes())
s.Require().Equal(limitedGasStdTx.Fee.Gas, uint64(100)) s.Require().NoError(err)
s.Require().Equal(len(limitedGasStdTx.Msgs), 1) txBuilder, err = txCfg.WrapTxBuilder(limitedGasStdTx)
s.Require().Equal(0, len(limitedGasStdTx.GetSignatures())) s.Require().NoError(err)
s.Require().Equal(txBuilder.GetTx().GetGas(), uint64(100))
s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
s.Require().Equal(0, len(txBuilder.GetTx().GetSignatures()))
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
s.Require().NoError(err)
var coins sdk.Coins
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err)
startTokens := coins.AmountOf(s.cfg.BondDenom)
// Test generate sendTx, estimate gas // Test generate sendTx, estimate gas
finalGeneratedTx, err := bankcli.MsgSendExec( finalGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
account.GetAddress(), account.GetAddress(),
sdk.NewCoins( sdk.NewCoins(sendTokens),
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -218,9 +233,12 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
) )
s.Require().NoError(err) s.Require().NoError(err)
finalStdTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, finalGeneratedTx.String()) finalStdTx, err := txCfg.TxJSONDecoder()(finalGeneratedTx.Bytes())
s.Require().Equal(uint64(flags.DefaultGasLimit), finalStdTx.Fee.Gas) s.Require().NoError(err)
s.Require().Equal(len(finalStdTx.Msgs), 1) txBuilder, err = txCfg.WrapTxBuilder(finalStdTx)
s.Require().NoError(err)
s.Require().Equal(uint64(flags.DefaultGasLimit), txBuilder.GetTx().GetGas())
s.Require().Equal(len(finalStdTx.GetMsgs()), 1)
// Write the output to disk // Write the output to disk
unsignedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String()) unsignedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String())
@ -245,11 +263,13 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
// Sign transaction // Sign transaction
signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name())
s.Require().NoError(err) s.Require().NoError(err)
signedFinalTx, err := txCfg.TxJSONDecoder()(signedTx.Bytes())
signedFinalTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, signedTx.String()) s.Require().NoError(err)
s.Require().Equal(len(signedFinalTx.Msgs), 1) txBuilder, err = val1.ClientCtx.TxConfig.WrapTxBuilder(signedFinalTx)
s.Require().Equal(1, len(signedFinalTx.GetSignatures())) s.Require().NoError(err)
s.Require().Equal(val1.Address.String(), signedFinalTx.GetSigners()[0].String()) s.Require().Equal(len(txBuilder.GetTx().GetMsgs()), 1)
s.Require().Equal(1, len(txBuilder.GetTx().GetSignatures()))
s.Require().Equal(val1.Address.String(), txBuilder.GetTx().GetSigners()[0].String())
// Write the output to disk // Write the output to disk
signedTxFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), signedTx.String()) signedTxFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), signedTx.String())
@ -261,11 +281,9 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
s.Require().True(strings.Contains(res.String(), "[OK]")) s.Require().True(strings.Contains(res.String(), "[OK]"))
// Ensure foo has right amount of funds // Ensure foo has right amount of funds
startTokens := sdk.TokensFromConsensusPower(400) resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
s.Require().NoError(err) s.Require().NoError(err)
var coins sdk.Coins
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Equal(startTokens, coins.AmountOf(s.cfg.BondDenom)) s.Require().Equal(startTokens, coins.AmountOf(s.cfg.BondDenom))
@ -291,7 +309,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Equal(sendTokens, coins.AmountOf(s.cfg.BondDenom)) s.Require().Equal(sendTokens.Amount, coins.AmountOf(s.cfg.BondDenom))
// Ensure origin account state // Ensure origin account state
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address) resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address)
@ -299,11 +317,9 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Equal(sdk.NewInt(389999990), coins.AmountOf(s.cfg.BondDenom))
} }
func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() { func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
s.T().SkipNow() // TODO check encoding.
val1 := s.network.Validators[0] val1 := s.network.Validators[0]
codec := codec2.New() codec := codec2.New()
@ -312,14 +328,10 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
val1.ClientCtx.Codec = codec val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig. // Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err) s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()})
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
s.Require().NoError(err) s.Require().NoError(err)
// Send coins from validator to multisig. // Send coins from validator to multisig.
@ -374,7 +386,7 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
defer cleanup3() defer cleanup3()
exec, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name()) exec, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name())
s.Require().NoError(err) s.Require().Error(err)
fmt.Printf("%s", exec) fmt.Printf("%s", exec)
} }
@ -382,15 +394,13 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
func (s *IntegrationTestSuite) TestCLIEncode() { func (s *IntegrationTestSuite) TestCLIEncode() {
val1 := s.network.Validators[0] val1 := s.network.Validators[0]
sendTokens := sdk.TokensFromConsensusPower(10) sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10))
normalGeneratedTx, err := bankcli.MsgSendExec( normalGeneratedTx, err := bankcli.MsgSendExec(
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
val1.Address, val1.Address,
sdk.NewCoins( sdk.NewCoins(sendTokens),
sdk.NewCoin(s.cfg.BondDenom, sendTokens),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -402,7 +412,7 @@ func (s *IntegrationTestSuite) TestCLIEncode() {
savedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String()) savedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String())
defer cleanup() defer cleanup()
// Enconde // Encode
encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name()) encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name())
s.Require().NoError(err) s.Require().NoError(err)
@ -412,12 +422,15 @@ func (s *IntegrationTestSuite) TestCLIEncode() {
decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64) decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64)
s.Require().NoError(err) s.Require().NoError(err)
theTx := unmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, decodedTx.String()) txCfg := val1.ClientCtx.TxConfig
s.Require().Equal("deadbeef", theTx.Memo) theTx, err := txCfg.TxJSONDecoder()(decodedTx.Bytes())
s.Require().NoError(err)
txBuilder, err := val1.ClientCtx.TxConfig.WrapTxBuilder(theTx)
s.Require().NoError(err)
s.Require().Equal("deadbeef", txBuilder.GetTx().GetMemo())
} }
func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
s.T().SkipNow()
val1 := s.network.Validators[0] val1 := s.network.Validators[0]
codec := codec2.New() codec := codec2.New()
@ -426,25 +439,30 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
val1.ClientCtx.Codec = codec val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig. // Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err) s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err) s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()}) multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
s.Require().NoError(err) s.Require().NoError(err)
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
s.Require().NoError(err)
var coins sdk.Coins
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err)
intialCoins := coins
// Send coins from validator to multisig. // Send coins from validator to multisig.
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
_, err = bankcli.MsgSendExec( _, err = bankcli.MsgSendExec(
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
multisigInfo.GetAddress(), multisigInfo.GetAddress(),
sdk.NewCoins( sdk.NewCoins(sendTokens),
sendTokens,
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -454,13 +472,13 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
s.Require().NoError(s.network.WaitForNextBlock()) s.Require().NoError(s.network.WaitForNextBlock())
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress()) resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
s.Require().NoError(err) s.Require().NoError(err)
var coins sdk.Coins
err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Equal(sendTokens.Amount, coins.AmountOf(s.cfg.BondDenom)) diff, _ := coins.SafeSub(intialCoins)
s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom))
// Generate multisig transaction. // Generate multisig transaction.
multiGeneratedTx, err := bankcli.MsgSendExec( multiGeneratedTx, err := bankcli.MsgSendExec(
@ -514,7 +532,6 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
} }
func (s *IntegrationTestSuite) TestCLIMultisign() { func (s *IntegrationTestSuite) TestCLIMultisign() {
s.T().SkipNow()
val1 := s.network.Validators[0] val1 := s.network.Validators[0]
codec := codec2.New() codec := codec2.New()
@ -523,14 +540,13 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
val1.ClientCtx.Codec = codec val1.ClientCtx.Codec = codec
// Generate 2 accounts and a multisig. // Generate 2 accounts and a multisig.
account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err) s.Require().NoError(err)
account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err) s.Require().NoError(err)
multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()}) multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi)
s.Require().NoError(err) s.Require().NoError(err)
// Send coins from validator to multisig. // Send coins from validator to multisig.
@ -539,9 +555,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
val1.ClientCtx, val1.ClientCtx,
val1.Address, val1.Address,
multisigInfo.GetAddress(), multisigInfo.GetAddress(),
sdk.NewCoins( sdk.NewCoins(sendTokens),
sendTokens,
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
@ -593,8 +607,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
defer cleanup3() defer cleanup3()
// Does not work in offline mode. // Does not work in offline mode.
val1.ClientCtx.Offline = true _, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name())
_, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
s.Require().EqualError(err, "couldn't verify signature") s.Require().EqualError(err, "couldn't verify signature")
val1.ClientCtx.Offline = false val1.ClientCtx.Offline = false
@ -617,7 +630,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
clientCtx := client.Context{}.WithOffline(true) clientCtx := client.Context{}.WithOffline(true)
clientCtx = clientCtx.WithTxConfig(simappparams.MakeEncodingConfig().TxConfig) clientCtx = clientCtx.WithTxConfig(simapp.MakeEncodingConfig().TxConfig)
cmd := authcli.GetBroadcastCommand() cmd := authcli.GetBroadcastCommand()
_ = testutil.ApplyMockIODiscardOutErr(cmd) _ = testutil.ApplyMockIODiscardOutErr(cmd)
@ -628,7 +641,8 @@ func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
clientCtx := client.Context{} clientCtx := client.Context{}
clientCtx = clientCtx.WithTxConfig(simappparams.MakeEncodingConfig().TxConfig) txCfg := simapp.MakeEncodingConfig().TxConfig
clientCtx = clientCtx.WithTxConfig(txCfg)
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
@ -639,9 +653,17 @@ func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
t.Cleanup(cleanFunc) t.Cleanup(cleanFunc)
// Create new file with tx // Create new file with tx
txContents := []byte("{\"type\":\"cosmos-sdk/StdTx\",\"value\":{\"msg\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"from_address\":\"cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw\",\"to_address\":\"cosmos1wc8mpr8m3sy3ap3j7fsgqfzx36um05pystems4\",\"amount\":[{\"denom\":\"stake\",\"amount\":\"10000\"}]}}],\"fee\":{\"amount\":[],\"gas\":\"200000\"},\"signatures\":null,\"memo\":\"\"}}") builder := txCfg.NewTxBuilder()
builder.SetGasLimit(200000)
from, err := sdk.AccAddressFromBech32("cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw")
require.NoError(t, err)
to, err := sdk.AccAddressFromBech32("cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw")
require.NoError(t, err)
err = builder.SetMsgs(banktypes.NewMsgSend(from, to, sdk.Coins{sdk.NewInt64Coin("stake", 10000)}))
require.NoError(t, err)
txContents, err := txCfg.TxJSONEncoder()(builder.GetTx())
txFileName := filepath.Join(testDir, "tx.json") txFileName := filepath.Join(testDir, "tx.json")
err := ioutil.WriteFile(txFileName, txContents, 0644) err = ioutil.WriteFile(txFileName, txContents, 0644)
require.NoError(t, err) require.NoError(t, err)
cmd.SetArgs([]string{txFileName}) cmd.SetArgs([]string{txFileName})
@ -654,8 +676,3 @@ func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) {
func TestIntegrationTestSuite(t *testing.T) { func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite)) suite.Run(t, new(IntegrationTestSuite))
} }
func unmarshalStdTx(t require.TestingT, c codec.JSONMarshaler, s string) (stdTx authtypes.StdTx) {
require.Nil(t, c.UnmarshalJSON([]byte(s), &stdTx))
return stdTx
}

View File

@ -3,6 +3,7 @@ package cli
import ( import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -37,7 +38,12 @@ func GetDecodeCommand() *cobra.Command {
return err return err
} }
return clientCtx.PrintOutput(tx) json, err := clientCtx.TxConfig.TxJSONEncoder()(tx)
if err != nil {
return err
}
return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
}, },
} }

View File

@ -2,6 +2,7 @@ package cli
import ( import (
"encoding/base64" "encoding/base64"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -10,13 +11,6 @@ import (
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
) )
// txEncodeRespStr implements a simple Stringer wrapper for a encoded tx.
type txEncodeRespStr string
func (txr txEncodeRespStr) String() string {
return string(txr)
}
// GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into // GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into
// Amino-serialized bytes // Amino-serialized bytes
func GetEncodeCommand() *cobra.Command { func GetEncodeCommand() *cobra.Command {
@ -44,8 +38,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea
// base64 encode the encoded tx bytes // base64 encode the encoded tx bytes
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes) txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
response := txEncodeRespStr(txBytesBase64) return clientCtx.PrintString(fmt.Sprintf("%s\n", txBytesBase64))
return clientCtx.PrintOutput(response)
}, },
} }

View File

@ -23,15 +23,17 @@ func TestGetCommandEncode(t *testing.T) {
authtypes.RegisterCodec(encodingConfig.Amino) authtypes.RegisterCodec(encodingConfig.Amino)
sdk.RegisterCodec(encodingConfig.Amino) sdk.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig txCfg := encodingConfig.TxConfig
// Build a test transaction // Build a test transaction
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) builder := txCfg.NewTxBuilder()
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo") builder.SetGasLimit(50000)
JSONEncoded, err := txGen.TxJSONEncoder()(stdTx) builder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin("atom", 150)})
builder.SetMemo("foomemo")
jsonEncoded, err := txCfg.TxJSONEncoder()(builder.GetTx())
require.NoError(t, err) require.NoError(t, err)
txFile, cleanup := testutil.WriteToNewTempFile(t, string(JSONEncoded)) txFile, cleanup := testutil.WriteToNewTempFile(t, string(jsonEncoded))
txFileName := txFile.Name() txFileName := txFile.Name()
t.Cleanup(cleanup) t.Cleanup(cleanup)
@ -58,15 +60,17 @@ func TestGetCommandDecode(t *testing.T) {
sdk.RegisterCodec(encodingConfig.Amino) sdk.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig txCfg := encodingConfig.TxConfig
clientCtx = clientCtx.WithTxConfig(txGen) clientCtx = clientCtx.WithTxConfig(txCfg)
// Build a test transaction // Build a test transaction
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) builder := txCfg.NewTxBuilder()
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo") builder.SetGasLimit(50000)
builder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin("atom", 150)})
builder.SetMemo("foomemo")
// Encode transaction // Encode transaction
txBytes, err := clientCtx.TxConfig.TxEncoder()(stdTx) txBytes, err := clientCtx.TxConfig.TxEncoder()(builder.GetTx())
require.NoError(t, err) require.NoError(t, err)
// Convert the transaction into base64 encoded string // Convert the transaction into base64 encoded string

View File

@ -11,13 +11,14 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig" "github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/types"
) )
@ -60,13 +61,27 @@ recommended to set such parameters manually.
func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error { func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) { return func(cmd *cobra.Command, args []string) (err error) {
clientCtx := client.GetClientContextFromCmd(cmd) clientCtx := client.GetClientContextFromCmd(cmd)
cdc := clientCtx.Codec clientCtx, err = client.ReadTxCommandFlags(clientCtx, cmd.Flags())
tx, err := authclient.ReadTxFromFile(clientCtx, args[0]) if err != nil {
stdTx := tx.(types.StdTx) return err
}
parsedTx, err := authclient.ReadTxFromFile(clientCtx, args[0])
if err != nil { if err != nil {
return return
} }
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED {
txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(parsedTx)
if err != nil {
return err
}
backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
inBuf := bufio.NewReader(cmd.InOrStdin()) inBuf := bufio.NewReader(cmd.InOrStdin())
@ -85,63 +100,53 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold)
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys)) multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir)
if err != nil {
return errors.Wrap(err, "error creating tx builder from flags")
}
if !clientCtx.Offline { if !clientCtx.Offline {
accnum, seq, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress()) accnum, seq, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
if err != nil { if err != nil {
return err return err
} }
txBldr = txBldr.WithAccountNumber(accnum).WithSequence(seq) txFactory = txFactory.WithAccountNumber(accnum).WithSequence(seq)
} }
// read each signature and add it to the multisig if valid // read each signature and add it to the multisig if valid
for i := 2; i < len(args); i++ { for i := 2; i < len(args); i++ {
stdSig, err := readAndUnmarshalStdSignature(cdc, args[i]) sigs, err := unmarshalSignatureJSON(clientCtx, args[i])
if err != nil { if err != nil {
return err return err
} }
// Validate each signature signingData := signing.SignerData{
sigBytes := types.StdSignBytes( ChainID: txFactory.ChainID(),
txBldr.ChainID(), txBldr.AccountNumber(), txBldr.Sequence(), AccountNumber: txFactory.AccountNumber(),
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), AccountSequence: txFactory.Sequence(),
) }
if ok := stdSig.GetPubKey().VerifyBytes(sigBytes, stdSig.Signature); !ok {
for _, sig := range sigs {
err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, txCfg.SignModeHandler(), txBuilder.GetTx())
if err != nil {
return fmt.Errorf("couldn't verify signature") return fmt.Errorf("couldn't verify signature")
} }
sigV2, err := types.StdSignatureToSignatureV2(cdc, stdSig) if err := multisig.AddSignatureV2(multisigSig, sig, multisigPub.PubKeys); err != nil {
if err != nil {
return nil
}
if err := multisig.AddSignatureV2(multisigSig, sigV2, multisigPub.PubKeys); err != nil {
return err return err
} }
} }
}
sigBz, err := types.SignatureDataToAminoSignature(cdc, multisigSig) sigV2 := signingtypes.SignatureV2{
PubKey: multisigPub,
Data: multisigSig,
}
err = txBuilder.SetSignatures(sigV2)
if err != nil { if err != nil {
return err return err
} }
newStdSig := types.StdSignature{Signature: sigBz, PubKey: multisigPub.Bytes()} //nolint:staticcheck
newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []types.StdSignature{newStdSig}, stdTx.GetMemo()) //nolint:staticcheck
var json []byte
sigOnly, _ := cmd.Flags().GetBool(flagSigOnly) sigOnly, _ := cmd.Flags().GetBool(flagSigOnly)
if sigOnly {
json, err = cdc.MarshalJSON(newTx.Signatures[0])
} else {
json, err = cdc.MarshalJSON(newTx)
}
json, err := marshalSignatureJSON(txCfg, txBuilder, sigOnly)
if err != nil { if err != nil {
return err return err
} }
@ -158,18 +163,14 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
} }
defer fp.Close() defer fp.Close()
fmt.Fprintf(fp, "%s\n", json) return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
return
} }
} }
func readAndUnmarshalStdSignature(cdc *codec.Codec, filename string) (stdSig types.StdSignature, err error) { //nolint:staticcheck func unmarshalSignatureJSON(clientCtx client.Context, filename string) (sigs []signingtypes.SignatureV2, err error) {
var bytes []byte var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil { if bytes, err = ioutil.ReadFile(filename); err != nil {
return return
} }
if err = cdc.UnmarshalJSON(bytes, &stdSig); err != nil { return clientCtx.TxConfig.UnmarshalSignatureJSON(bytes)
return
}
return
} }

View File

@ -1,7 +1,6 @@
package cli package cli
import ( import (
"bufio"
"fmt" "fmt"
"os" "os"
@ -9,10 +8,10 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/types"
) )
const ( const (
@ -61,12 +60,13 @@ account key. It implies --signature-only.
func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd) clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
txBldr, err := types.NewTxBuilderFromFlags(bufio.NewReader(cmd.InOrStdin()), cmd.Flags(), clientCtx.HomeDir)
if err != nil { if err != nil {
return err return err
} }
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
txCfg := clientCtx.TxConfig
generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
var ( var (
@ -97,34 +97,34 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return err return err
} }
} }
scanner := authclient.NewBatchScanner(txCfg, infile)
scanner := authclient.NewBatchScanner(clientCtx.JSONMarshaler, infile) for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
unsignedStdTx := scanner.Tx()
for sequence := txBldr.Sequence(); scanner.Scan(); sequence++ { txFactory = txFactory.WithSequence(sequence)
var stdTx types.StdTx txBuilder, err := txCfg.WrapTxBuilder(unsignedStdTx)
if err != nil {
unsignedStdTx := scanner.StdTx() return err
txBldr = txBldr.WithSequence(sequence) }
if multisigAddr.Empty() { if multisigAddr.Empty() {
from, _ := cmd.Flags().GetString(flags.FlagFrom) from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly) _, fromName, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly)
if err != nil { if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err) return fmt.Errorf("error getting account from keybase: %w", err)
} }
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true)
stdTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, unsignedStdTx, false, true)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
stdTx, err = authclient.SignStdTxWithSignerAddress(txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), unsignedStdTx, true) err = authclient.SignTxWithSignerAddress(txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, true)
}
if err != nil { if err != nil {
return err return err
} }
}
json, err := getSignatureJSON(clientCtx.JSONMarshaler, stdTx, generateSignatureOnly) json, err := marshalSignatureJSON(txCfg, txBuilder, generateSignatureOnly)
if err != nil { if err != nil {
return err return err
} }
@ -206,20 +206,31 @@ func preSignCmd(cmd *cobra.Command, _ []string) {
func makeSignCmd() func(cmd *cobra.Command, args []string) error { func makeSignCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd) clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) if err != nil {
return err
}
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
clientCtx, txF, newTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil {
return err
}
if txF.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED {
txF = txF.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(newTx)
if err != nil { if err != nil {
return err return err
} }
stdTx := tx.(types.StdTx)
// if --signature-only is on, then override --append // if --signature-only is on, then override --append
var newTx types.StdTx
generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig) multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig)
from, _ := cmd.Flags().GetString(flags.FlagFrom) from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly) _, fromName, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly)
if err != nil { if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err) return fmt.Errorf("error getting account from keybase: %w", err)
} }
@ -232,23 +243,22 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
return err return err
} }
newTx, err = authclient.SignStdTxWithSignerAddress( err = authclient.SignTxWithSignerAddress(
txBldr, clientCtx, multisigAddr, fromName, stdTx, clientCtx.Offline, txF, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline,
) )
generateSignatureOnly = true generateSignatureOnly = true
} else { } else {
append, _ := cmd.Flags().GetBool(flagAppend) flagAppend, _ := cmd.Flags().GetBool(flagAppend)
appendSig := append && !generateSignatureOnly appendSig := flagAppend && !generateSignatureOnly
newTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, stdTx, appendSig, clientCtx.Offline) if appendSig {
if err != nil { err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline)
return err
} }
} }
if err != nil { if err != nil {
return err return err
} }
json, err := getSignatureJSON(clientCtx.JSONMarshaler, newTx, generateSignatureOnly) json, err := marshalSignatureJSON(txCfg, txBuilder, generateSignatureOnly)
if err != nil { if err != nil {
return err return err
} }
@ -265,15 +275,20 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
} }
defer fp.Close() defer fp.Close()
fmt.Fprintf(fp, "%s\n", json) return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
return nil
} }
} }
func getSignatureJSON(cdc codec.JSONMarshaler, newTx types.StdTx, generateSignatureOnly bool) ([]byte, error) { func marshalSignatureJSON(txConfig client.TxConfig, txBldr client.TxBuilder, generateSignatureOnly bool) ([]byte, error) {
parsedTx := txBldr.GetTx()
if generateSignatureOnly { if generateSignatureOnly {
return cdc.MarshalJSON(newTx.Signatures[0]) sigs, err := parsedTx.GetSignaturesV2()
if err != nil {
return nil, err
}
return txConfig.MarshalSignatureJSON(sigs)
} }
return cdc.MarshalJSON(newTx) return txConfig.TxJSONEncoder()(parsedTx)
} }

View File

@ -1,18 +1,16 @@
package cli package cli
import ( import (
"bufio"
"fmt" "fmt"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig" "github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/auth/types" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
) )
func GetValidateSignaturesCommand() *cobra.Command { func GetValidateSignaturesCommand() *cobra.Command {
@ -41,11 +39,15 @@ transaction will be not be performed as that will require RPC communication with
func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error { func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd) clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
clientCtx, txBldr, stdTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil { if err != nil {
return err return err
} }
stdTx := tx.(types.StdTx)
if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) { if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) {
return fmt.Errorf("signatures validation failed") return fmt.Errorf("signatures validation failed")
@ -59,17 +61,22 @@ func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error {
// expected signers. In addition, if offline has not been supplied, the signature is // expected signers. In addition, if offline has not been supplied, the signature is
// verified over the transaction sign bytes. Returns false if the validation fails. // verified over the transaction sign bytes. Returns false if the validation fails.
func printAndValidateSigs( func printAndValidateSigs(
cmd *cobra.Command, clientCtx client.Context, chainID string, stdTx types.StdTx, offline bool, cmd *cobra.Command, clientCtx client.Context, chainID string, tx sdk.Tx, offline bool,
) bool { ) bool {
cmd.Println("Signers:") sigTx := tx.(authsigning.SigVerifiableTx)
signers := stdTx.GetSigners() signModeHandler := clientCtx.TxConfig.SignModeHandler()
cmd.Println("Signers:")
signers := sigTx.GetSigners()
for i, signer := range signers { for i, signer := range signers {
cmd.Printf(" %v: %v\n", i, signer.String()) cmd.Printf(" %v: %v\n", i, signer.String())
} }
success := true success := true
sigs := stdTx.Signatures sigs, err := sigTx.GetSignaturesV2()
if err != nil {
panic(err)
}
cmd.Println("") cmd.Println("")
cmd.Println("Signatures:") cmd.Println("Signatures:")
@ -79,9 +86,10 @@ func printAndValidateSigs(
for i, sig := range sigs { for i, sig := range sigs {
var ( var (
pubKey = sig.PubKey
multiSigHeader string multiSigHeader string
multiSigMsg string multiSigMsg string
sigAddr = sdk.AccAddress(sig.GetPubKey().Address()) sigAddr = sdk.AccAddress(pubKey.Address())
sigSanity = "OK" sigSanity = "OK"
) )
@ -93,40 +101,21 @@ func printAndValidateSigs(
// Validate the actual signature over the transaction bytes since we can // Validate the actual signature over the transaction bytes since we can
// reach out to a full node to query accounts. // reach out to a full node to query accounts.
if !offline && success { if !offline && success {
acc, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccount(clientCtx, sigAddr) accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, sigAddr)
if err != nil { if err != nil {
cmd.Printf("failed to get account: %s\n", sigAddr) cmd.Printf("failed to get account: %s\n", sigAddr)
return false return false
} }
sigBytes := types.StdSignBytes( signingData := authsigning.SignerData{
chainID, acc.GetAccountNumber(), acc.GetSequence(), ChainID: chainID,
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), AccountNumber: accNum,
) AccountSequence: accSeq,
if ok := sig.GetPubKey().VerifyBytes(sigBytes, sig.Signature); !ok {
sigSanity = "ERROR: signature invalid"
success = false
} }
err = authsigning.VerifySignature(pubKey, signingData, sig.Data, signModeHandler, sigTx)
if err != nil {
return false
} }
multiPK, ok := sig.GetPubKey().(multisig.PubKeyMultisigThreshold)
if ok {
var multiSig multisig.AminoMultisignature
clientCtx.Codec.MustUnmarshalBinaryBare(sig.Signature, &multiSig)
var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")
for i := 0; i < multiSig.BitArray.Count(); i++ {
if multiSig.BitArray.GetIndex(i) {
addr := sdk.AccAddress(multiPK.PubKeys[i].Address().Bytes())
b.WriteString(fmt.Sprintf(" %d: %s (weight: %d)\n", i, addr, 1))
}
}
multiSigHeader = fmt.Sprintf(" [multisig threshold: %d/%d]", multiPK.K, len(multiPK.PubKeys))
multiSigMsg = b.String()
} }
cmd.Printf(" %d: %s\t\t\t[%s]%s%s\n", i, sigAddr.String(), sigSanity, multiSigHeader, multiSigMsg) cmd.Printf(" %d: %s\t\t\t[%s]%s%s\n", i, sigAddr.String(), sigSanity, multiSigHeader, multiSigMsg)
@ -137,21 +126,13 @@ func printAndValidateSigs(
return success return success
} }
func readStdTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) ( func readTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (client.Context, tx.Factory, sdk.Tx, error) {
client.Context, types.TxBuilder, sdk.Tx, error,
) {
stdTx, err := authclient.ReadTxFromFile(clientCtx, filename) stdTx, err := authclient.ReadTxFromFile(clientCtx, filename)
if err != nil { if err != nil {
return client.Context{}, types.TxBuilder{}, types.StdTx{}, err return clientCtx, tx.Factory{}, nil, err
} }
inBuf := bufio.NewReader(cmd.InOrStdin()) txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
clientCtx = clientCtx.WithInput(inBuf)
txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir) return clientCtx, txFactory, stdTx, nil
if err != nil {
return client.Context{}, types.TxBuilder{}, types.StdTx{}, err
}
return clientCtx, txBldr, stdTx, nil
} }

View File

@ -10,10 +10,9 @@ import (
"strings" "strings"
"github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/jsonpb"
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@ -38,81 +37,6 @@ func (gr GasEstimateResponse) String() string {
return fmt.Sprintf("gas estimate: %d", gr.GasEstimate) return fmt.Sprintf("gas estimate: %d", gr.GasEstimate)
} }
// GenerateOrBroadcastMsgs creates a StdTx given a series of messages. If
// the provided context has generate-only enabled, the tx will only be printed
// to STDOUT in a fully offline manner. Otherwise, the tx will be signed and
// broadcasted.
func GenerateOrBroadcastMsgs(clientCtx client.Context, txBldr authtypes.TxBuilder, msgs []sdk.Msg) error {
if clientCtx.GenerateOnly {
return PrintUnsignedStdTx(txBldr, clientCtx, msgs)
}
return CompleteAndBroadcastTxCLI(txBldr, clientCtx, msgs)
}
// CompleteAndBroadcastTxCLI implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
// sequence set. In addition, it builds and signs a transaction with the
// supplied messages. Finally, it broadcasts the signed transaction to a node.
func CompleteAndBroadcastTxCLI(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) error {
txBldr, err := PrepareTxBuilder(txBldr, clientCtx)
if err != nil {
return err
}
fromName := clientCtx.GetFromName()
if txBldr.SimulateAndExecute() || clientCtx.Simulate {
txBldr, err = EnrichWithGas(txBldr, clientCtx, msgs)
if err != nil {
return err
}
gasEst := GasEstimateResponse{GasEstimate: txBldr.Gas()}
_, _ = fmt.Fprintf(os.Stderr, "%s\n", gasEst.String())
}
if clientCtx.Simulate {
return nil
}
if !clientCtx.SkipConfirm {
stdSignMsg, err := txBldr.BuildSignMsg(msgs)
if err != nil {
return err
}
json, err := clientCtx.JSONMarshaler.MarshalJSON(stdSignMsg)
if err != nil {
return err
}
_, _ = fmt.Fprintf(os.Stderr, "%s\n\n", json)
buf := bufio.NewReader(os.Stdin)
ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr)
if err != nil || !ok {
_, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction")
return err
}
}
// build and sign the transaction
txBytes, err := txBldr.BuildAndSign(fromName, msgs)
if err != nil {
return err
}
// broadcast to a Tendermint node
res, err := clientCtx.BroadcastTx(txBytes)
if err != nil {
return err
}
return clientCtx.PrintOutput(res)
}
// EnrichWithGas calculates the gas estimate that would be consumed by the // EnrichWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly. // transaction and set the transaction's respective value accordingly.
func EnrichWithGas(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) (authtypes.TxBuilder, error) { func EnrichWithGas(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) (authtypes.TxBuilder, error) {
@ -148,74 +72,52 @@ func CalculateGas(
} }
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout. // PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
func PrintUnsignedStdTx(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) error { func PrintUnsignedStdTx(txBldr tx.Factory, clientCtx client.Context, msgs []sdk.Msg) error {
stdTx, err := buildUnsignedStdTxOffline(txBldr, clientCtx, msgs) err := tx.GenerateOrBroadcastTxWithFactory(clientCtx, txBldr, msgs...)
if err != nil {
return err return err
}
json, err := clientCtx.JSONMarshaler.MarshalJSON(stdTx)
if err != nil {
return err
}
_, _ = fmt.Fprintf(clientCtx.Output, "%s\n", json)
return nil
} }
// SignStdTx appends a signature to a StdTx and returns a copy of it. If appendSig // SignTx appends a signature to a transaction. If appendSig
// is false, it replaces the signatures already attached with the new signature. // is false, it replaces the signatures already attached with the new signature.
// Don't perform online validation or lookups if offline is true. // Don't perform online validation or lookups if offline is true.
func SignStdTx( func SignTx(txFactory tx.Factory, clientCtx client.Context, name string, stdTx client.TxBuilder, offline bool) error {
txBldr authtypes.TxBuilder, clientCtx client.Context, name string, info, err := txFactory.Keybase().Key(name)
stdTx authtypes.StdTx, appendSig bool, offline bool,
) (authtypes.StdTx, error) {
var signedStdTx authtypes.StdTx
info, err := txBldr.Keybase().Key(name)
if err != nil { if err != nil {
return signedStdTx, err return err
} }
addr := sdk.AccAddress(info.GetPubKey().Address())
addr := info.GetPubKey().Address() if !isTxSigner(addr, stdTx.GetTx().GetSigners()) {
return fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
// check whether the address is a signer
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
} }
if !offline { if !offline {
txBldr, err = populateAccountFromState(txBldr, clientCtx, sdk.AccAddress(addr)) txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
if err != nil { if err != nil {
return signedStdTx, err return err
} }
} }
return txBldr.SignStdTx(name, stdTx, appendSig) return tx.Sign(txFactory, name, stdTx)
} }
// SignStdTxWithSignerAddress attaches a signature to a StdTx and returns a copy of a it. // SignTxWithSignerAddress attaches a signature to a transaction.
// Don't perform online validation or lookups if offline is true, else // Don't perform online validation or lookups if offline is true, else
// populate account and sequence numbers from a foreign account. // populate account and sequence numbers from a foreign account.
func SignStdTxWithSignerAddress( func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
txBldr authtypes.TxBuilder, clientCtx client.Context, name string, txBuilder client.TxBuilder, offline bool) (err error) {
addr sdk.AccAddress, name string, stdTx authtypes.StdTx, offline bool,
) (signedStdTx authtypes.StdTx, err error) {
// check whether the address is a signer // check whether the address is a signer
if !isTxSigner(addr, stdTx.GetSigners()) { if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) {
return signedStdTx, fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name) return fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
} }
if !offline { if !offline {
txBldr, err = populateAccountFromState(txBldr, clientCtx, addr) txFactory, err = populateAccountFromState(txFactory, clientCtx, addr)
if err != nil { if err != nil {
return signedStdTx, err return err
} }
} }
return txBldr.SignStdTx(name, stdTx, false) return tx.Sign(txFactory, name, txBuilder)
} }
// Read and decode a StdTx from the given filename. Can pass "-" to read from stdin. // Read and decode a StdTx from the given filename. Can pass "-" to read from stdin.
@ -236,21 +138,21 @@ func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error)
} }
// NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r. // NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r.
func NewBatchScanner(cdc codec.JSONMarshaler, r io.Reader) *BatchScanner { func NewBatchScanner(cfg client.TxConfig, r io.Reader) *BatchScanner {
return &BatchScanner{Scanner: bufio.NewScanner(r), cdc: cdc} return &BatchScanner{Scanner: bufio.NewScanner(r), cfg: cfg}
} }
// BatchScanner provides a convenient interface for reading batch data such as a file // BatchScanner provides a convenient interface for reading batch data such as a file
// of newline-delimited JSON encoded StdTx. // of newline-delimited JSON encoded StdTx.
type BatchScanner struct { type BatchScanner struct {
*bufio.Scanner *bufio.Scanner
stdTx authtypes.StdTx theTx sdk.Tx
cdc codec.JSONMarshaler cfg client.TxConfig
unmarshalErr error unmarshalErr error
} }
// StdTx returns the most recent StdTx unmarshalled by a call to Scan. // Tx returns the most recent Tx unmarshalled by a call to Scan.
func (bs BatchScanner) StdTx() authtypes.StdTx { return bs.stdTx } func (bs BatchScanner) Tx() sdk.Tx { return bs.theTx }
// UnmarshalErr returns the first unmarshalling error that was encountered by the scanner. // UnmarshalErr returns the first unmarshalling error that was encountered by the scanner.
func (bs BatchScanner) UnmarshalErr() error { return bs.unmarshalErr } func (bs BatchScanner) UnmarshalErr() error { return bs.unmarshalErr }
@ -261,7 +163,9 @@ func (bs *BatchScanner) Scan() bool {
return false return false
} }
if err := bs.cdc.UnmarshalJSON(bs.Bytes(), &bs.stdTx); err != nil && bs.unmarshalErr == nil { tx, err := bs.cfg.TxJSONDecoder()(bs.Bytes())
bs.theTx = tx
if err != nil && bs.unmarshalErr == nil {
bs.unmarshalErr = err bs.unmarshalErr = err
return false return false
} }
@ -270,8 +174,8 @@ func (bs *BatchScanner) Scan() bool {
} }
func populateAccountFromState( func populateAccountFromState(
txBldr authtypes.TxBuilder, clientCtx client.Context, addr sdk.AccAddress, txBldr tx.Factory, clientCtx client.Context, addr sdk.AccAddress,
) (authtypes.TxBuilder, error) { ) (tx.Factory, error) {
num, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr) num, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
if err != nil { if err != nil {
@ -316,56 +220,6 @@ func parseQueryResponse(bz []byte) (sdk.SimulationResponse, error) {
return simRes, nil return simRes, nil
} }
// PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx.
func PrepareTxBuilder(txBldr authtypes.TxBuilder, clientCtx client.Context) (authtypes.TxBuilder, error) {
from := clientCtx.GetFromAddress()
accGetter := clientCtx.AccountRetriever
if err := accGetter.EnsureExists(clientCtx, from); err != nil {
return txBldr, err
}
txbldrAccNum, txbldrAccSeq := txBldr.AccountNumber(), txBldr.Sequence()
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txbldrAccNum == 0 || txbldrAccSeq == 0 {
num, seq, err := accGetter.GetAccountNumberSequence(clientCtx, from)
if err != nil {
return txBldr, err
}
if txbldrAccNum == 0 {
txBldr = txBldr.WithAccountNumber(num)
}
if txbldrAccSeq == 0 {
txBldr = txBldr.WithSequence(seq)
}
}
return txBldr, nil
}
func buildUnsignedStdTxOffline(txBldr authtypes.TxBuilder, clientCtx client.Context, msgs []sdk.Msg) (stdTx authtypes.StdTx, err error) {
if txBldr.SimulateAndExecute() {
if clientCtx.Offline {
return stdTx, errors.New("cannot estimate gas in offline mode")
}
txBldr, err = EnrichWithGas(txBldr, clientCtx, msgs)
if err != nil {
return stdTx, err
}
_, _ = fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas())
}
stdSignMsg, err := txBldr.BuildSignMsg(msgs)
if err != nil {
return stdTx, err
}
return authtypes.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
}
func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool { func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
for _, s := range signers { for _, s := range signers {
if bytes.Equal(user.Bytes(), s.Bytes()) { if bytes.Equal(user.Bytes(), s.Bytes()) {

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata" "github.com/cosmos/cosmos-sdk/testutil/testdata"
@ -149,8 +150,12 @@ func TestReadStdTxFromFile(t *testing.T) {
func TestBatchScanner_Scan(t *testing.T) { func TestBatchScanner_Scan(t *testing.T) {
t.Parallel() t.Parallel()
cdc := codec.New() encodingConfig := simappparams.MakeEncodingConfig()
sdk.RegisterCodec(cdc) std.RegisterCodec(encodingConfig.Amino)
txGen := encodingConfig.TxConfig
clientCtx := client.Context{}
clientCtx = clientCtx.WithTxConfig(txGen)
batch1 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"} batch1 := `{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"50000"},"signatures":[],"memo":"foomemo"}
{"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"10000"},"signatures":[],"memo":"foomemo"} {"msg":[],"fee":{"amount":[{"denom":"atom","amount":"150"}],"gas":"10000"},"signatures":[],"memo":"foomemo"}
@ -182,12 +187,12 @@ malformed
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
scanner, i := NewBatchScanner(cdc, strings.NewReader(tt.batch)), 0 scanner, i := NewBatchScanner(clientCtx.TxConfig, strings.NewReader(tt.batch)), 0
for scanner.Scan() { for scanner.Scan() {
_ = scanner.StdTx() _ = scanner.Tx()
i++ i++
} }
t.Log(scanner.theTx)
require.Equal(t, tt.wantScannerError, scanner.Err() != nil) require.Equal(t, tt.wantScannerError, scanner.Err() != nil)
require.Equal(t, tt.wantUnmarshalError, scanner.UnmarshalErr() != nil) require.Equal(t, tt.wantUnmarshalError, scanner.UnmarshalErr() != nil)
require.Equal(t, tt.numTxs, i) require.Equal(t, tt.numTxs, i)
@ -206,48 +211,6 @@ func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder)
require.Equal(t, defaultEncoderBytes, encoderBytes) require.Equal(t, defaultEncoderBytes, encoderBytes)
} }
func TestPrepareTxBuilder(t *testing.T) {
cdc := makeCodec()
encodingConfig := simappparams.MakeEncodingConfig()
sdk.RegisterCodec(encodingConfig.Amino)
fromAddr := sdk.AccAddress("test-addr0000000000")
fromAddrStr := fromAddr.String()
var accNum uint64 = 10
var accSeq uint64 = 17
txGen := encodingConfig.TxConfig
clientCtx := client.Context{}
clientCtx = clientCtx.
WithTxConfig(txGen).
WithJSONMarshaler(encodingConfig.Marshaler).
WithAccountRetriever(client.TestAccountRetriever{Accounts: map[string]struct {
Address sdk.AccAddress
Num uint64
Seq uint64
}{
fromAddrStr: {
Address: fromAddr,
Num: accNum,
Seq: accSeq,
},
}}).
WithFromAddress(fromAddr)
bldr := authtypes.NewTxBuilder(
authtypes.DefaultTxEncoder(cdc), 0, 0,
200000, 1.1, false, "test-chain",
"test-builder", sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))),
sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(10000, sdk.Precision))})
bldr, err := PrepareTxBuilder(bldr, clientCtx)
require.NoError(t, err)
require.Equal(t, accNum, bldr.AccountNumber())
require.Equal(t, accSeq, bldr.Sequence())
}
func makeCodec() *codec.Codec { func makeCodec() *codec.Codec {
var cdc = codec.New() var cdc = codec.New()
sdk.RegisterCodec(cdc) sdk.RegisterCodec(cdc)

View File

@ -3,8 +3,9 @@ package tx
import ( import (
"fmt" "fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/signing"
@ -17,17 +18,19 @@ type generator struct {
encoder sdk.TxEncoder encoder sdk.TxEncoder
jsonDecoder sdk.TxDecoder jsonDecoder sdk.TxDecoder
jsonEncoder sdk.TxEncoder jsonEncoder sdk.TxEncoder
protoCodec *codec.ProtoCodec
} }
// NewTxConfig returns a new protobuf TxConfig using the provided Marshaler, PublicKeyCodec and SignModeHandler. // NewTxConfig returns a new protobuf TxConfig using the provided ProtoCodec, PublicKeyCodec and SignModeHandler.
func NewTxConfig(anyUnpacker codectypes.AnyUnpacker, pubkeyCodec types.PublicKeyCodec, signModeHandler signing.SignModeHandler) client.TxConfig { func NewTxConfig(protoCodec *codec.ProtoCodec, pubkeyCodec types.PublicKeyCodec, signModeHandler signing.SignModeHandler) client.TxConfig {
return &generator{ return &generator{
pubkeyCodec: pubkeyCodec, pubkeyCodec: pubkeyCodec,
handler: signModeHandler, handler: signModeHandler,
decoder: DefaultTxDecoder(anyUnpacker, pubkeyCodec), decoder: DefaultTxDecoder(protoCodec, pubkeyCodec),
encoder: DefaultTxEncoder(), encoder: DefaultTxEncoder(),
jsonDecoder: DefaultJSONTxDecoder(anyUnpacker, pubkeyCodec), jsonDecoder: DefaultJSONTxDecoder(protoCodec, pubkeyCodec),
jsonEncoder: DefaultJSONTxEncoder(), jsonEncoder: DefaultJSONTxEncoder(),
protoCodec: protoCodec,
} }
} }

View File

@ -3,6 +3,8 @@ package tx
import ( import (
"fmt" "fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/types/tx/signing"
@ -102,3 +104,50 @@ func decodeMultisignatures(bz []byte) ([][]byte, error) {
} }
return multisig.Signatures, nil return multisig.Signatures, nil
} }
func (g generator) MarshalSignatureJSON(sigs []signing.SignatureV2) ([]byte, error) {
descs := make([]*signing.SignatureDescriptor, len(sigs))
for i, sig := range sigs {
publicKey, err := g.pubkeyCodec.Encode(sig.PubKey)
if err != nil {
return nil, err
}
descData := signing.SignatureDataToProto(sig.Data)
descs[i] = &signing.SignatureDescriptor{
PublicKey: publicKey,
Data: descData,
}
}
toJSON := &signing.SignatureDescriptors{Signatures: descs}
return codec.ProtoMarshalJSON(toJSON)
}
func (g generator) UnmarshalSignatureJSON(bz []byte) ([]signing.SignatureV2, error) {
var sigDescs signing.SignatureDescriptors
err := g.protoCodec.UnmarshalJSON(bz, &sigDescs)
if err != nil {
return nil, err
}
sigs := make([]signing.SignatureV2, len(sigDescs.Signatures))
for i, desc := range sigDescs.Signatures {
pubKey, err := g.pubkeyCodec.Decode(desc.PublicKey)
if err != nil {
return nil, err
}
data := signing.SignatureDataFromProto(desc.Data)
sigs[i] = signing.SignatureV2{
PubKey: pubKey,
Data: data,
}
}
return sigs, nil
}

View File

@ -7,7 +7,6 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/legacy"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx" txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/types/tx/signing"
@ -46,29 +45,12 @@ func (s *StdTxBuilder) SetSignatures(signatures ...signing.SignatureV2) error {
sigs := make([]StdSignature, len(signatures)) sigs := make([]StdSignature, len(signatures))
for i, sig := range signatures { for i, sig := range signatures {
var pubKeyBz []byte stdSig, err := SignatureV2ToStdSignature(s.cdc, sig)
pubKey := sig.PubKey
if pubKey != nil {
pubKeyBz = pubKey.Bytes()
}
var (
sigBz []byte
err error
)
if sig.Data != nil {
sigBz, err = SignatureDataToAminoSignature(legacy.Cdc, sig.Data)
if err != nil { if err != nil {
return err return err
} }
}
sigs[i] = StdSignature{ sigs[i] = stdSig
PubKey: pubKeyBz,
Signature: sigBz,
}
} }
s.Signatures = sigs s.Signatures = sigs
@ -131,6 +113,38 @@ func (s StdTxConfig) TxJSONDecoder() sdk.TxDecoder {
return DefaultJSONTxDecoder(s.Cdc) return DefaultJSONTxDecoder(s.Cdc)
} }
func (s StdTxConfig) MarshalSignatureJSON(sigs []signing.SignatureV2) ([]byte, error) {
stdSigs := make([]StdSignature, len(sigs))
for i, sig := range sigs {
stdSig, err := SignatureV2ToStdSignature(s.Cdc, sig)
if err != nil {
return nil, err
}
stdSigs[i] = stdSig
}
return s.Cdc.MarshalJSON(stdSigs)
}
func (s StdTxConfig) UnmarshalSignatureJSON(bz []byte) ([]signing.SignatureV2, error) {
var stdSigs []StdSignature
err := s.Cdc.UnmarshalJSON(bz, &stdSigs)
if err != nil {
return nil, err
}
sigs := make([]signing.SignatureV2, len(stdSigs))
for i, stdSig := range stdSigs {
sig, err := StdSignatureToSignatureV2(s.Cdc, stdSig)
if err != nil {
return nil, err
}
sigs[i] = sig
}
return sigs, nil
}
func (s StdTxConfig) SignModeHandler() authsigning.SignModeHandler { func (s StdTxConfig) SignModeHandler() authsigning.SignModeHandler {
return LegacyAminoJSONHandler{} return LegacyAminoJSONHandler{}
} }

View File

@ -395,6 +395,33 @@ func StdSignatureToSignatureV2(cdc *codec.Codec, sig StdSignature) (signing.Sign
}, nil }, nil
} }
// SignatureV2ToStdSignature converts a SignatureV2 to a StdSignature
func SignatureV2ToStdSignature(cdc *codec.Codec, sig signing.SignatureV2) (StdSignature, error) {
var pubKeyBz []byte
pubKey := sig.PubKey
if pubKey != nil {
pubKeyBz = pubKey.Bytes()
}
var (
sigBz []byte
err error
)
if sig.Data != nil {
sigBz, err = SignatureDataToAminoSignature(cdc, sig.Data)
if err != nil {
return StdSignature{}, err
}
}
return StdSignature{
PubKey: pubKeyBz,
Signature: sigBz,
}, nil
}
func pubKeySigToSigData(cdc *codec.Codec, key crypto.PubKey, sig []byte) (signing.SignatureData, error) { func pubKeySigToSigData(cdc *codec.Codec, key crypto.PubKey, sig []byte) (signing.SignatureData, error) {
multiPK, ok := key.(multisig.PubKey) multiPK, ok := key.(multisig.PubKey)
if !ok { if !ok {

View File

@ -17,6 +17,7 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"
@ -133,16 +134,17 @@ $ %s gentx my-key-name --home=/path/to/home/dir --keyring-backend=os --chain-id=
return errors.Wrap(err, "failed to validate account in genesis") return errors.Wrap(err, "failed to validate account in genesis")
} }
txBldr, err := authtypes.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir) txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if err != nil { if err != nil {
return errors.Wrap(err, "error creating tx builder") return errors.Wrap(err, "error creating tx builder")
} }
txBldr = txBldr.WithTxEncoder(authclient.GetTxEncoder(clientCtx.Codec)) txGen := clientCtx.TxConfig
txBuilder := txGen.NewTxBuilder()
clientCtx = clientCtx.WithInput(inBuf).WithFromAddress(key.GetAddress()) clientCtx = clientCtx.WithInput(inBuf).WithFromAddress(key.GetAddress())
// create a 'create-validator' message // create a 'create-validator' message
txBldr, msg, err := cli.BuildCreateValidatorMsg(clientCtx, createValCfg, txBldr, true) txBldr, msg, err := cli.BuildCreateValidatorMsg(clientCtx, createValCfg, txFactory, true)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to build create-validator message") return errors.Wrap(err, "failed to build create-validator message")
} }
@ -167,7 +169,7 @@ $ %s gentx my-key-name --home=/path/to/home/dir --keyring-backend=os --chain-id=
} }
// sign the transaction and write it to the output file // sign the transaction and write it to the output file
signedTx, err := authclient.SignStdTx(txBldr, clientCtx, name, stdTx, false, true) err = authclient.SignTx(txFactory, clientCtx, name, txBuilder, true)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to sign std tx") return errors.Wrap(err, "failed to sign std tx")
} }
@ -180,7 +182,7 @@ $ %s gentx my-key-name --home=/path/to/home/dir --keyring-backend=os --chain-id=
} }
} }
if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil { if err := writeSignedGenTx(cdc, outputDocument, stdTx); err != nil {
return errors.Wrap(err, "failed to write signed gen tx") return errors.Wrap(err, "failed to write signed gen tx")
} }
@ -219,7 +221,7 @@ func readUnsignedGenTxFile(cdc codec.JSONMarshaler, r io.Reader) (authtypes.StdT
return stdTx, err return stdTx, err
} }
func writeSignedGenTx(cdc codec.JSONMarshaler, outputDocument string, tx authtypes.StdTx) error { func writeSignedGenTx(cdc codec.JSONMarshaler, outputDocument string, tx sdk.Tx) error {
outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return err return err

View File

@ -109,6 +109,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() {
fmt.Sprintf("--%s=%s", cli.FlagProposal, validPropFile.Name()), fmt.Sprintf("--%s=%s", cli.FlagProposal, validPropFile.Name()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
}, },
false, &sdk.TxResponse{}, 0, false, &sdk.TxResponse{}, 0,
@ -122,6 +123,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() {
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)).String()), fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
}, },
false, &sdk.TxResponse{}, 0, false, &sdk.TxResponse{}, 0,

View File

@ -14,7 +14,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/cosmos-sdk/x/staking/types"
) )
@ -503,7 +502,7 @@ func PrepareConfigForTxCreateValidator(flagSet *flag.FlagSet, moniker, nodeID, c
} }
// BuildCreateValidatorMsg makes a new MsgCreateValidator. // BuildCreateValidatorMsg makes a new MsgCreateValidator.
func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorConfig, txBldr authtypes.TxBuilder, generateOnly bool) (authtypes.TxBuilder, sdk.Msg, error) { func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorConfig, txBldr tx.Factory, generateOnly bool) (tx.Factory, sdk.Msg, error) {
amounstStr := config.Amount amounstStr := config.Amount
amount, err := sdk.ParseCoin(amounstStr) amount, err := sdk.ParseCoin(amounstStr)