Add support for protobuf TxGenerator and SIGN_MODE_DIRECT (#6385)

* Add TxWrapper, encoder, decoder and DirectModeHandler

* fix pkg name

* Update API and leave test TODO's

* Update TxWrapper API

* tests for tx wrapper (#6410)

* WIP: added test for direct mode handler

* updated code

* Add msg

* Update TxWrapper API

* Fix pubkey declaration

* Add pubkey for tests

* Fix SetFee

* Remove logs

* Avoid global var declaration for tests

* Add test for GetPubKeys

* Fix direct signing tests

* Add more test cases for GetSignBytes

* Revert SetFee API

* Remove logs

* Refactor tests

Co-authored-by: anilCSE <anil@vitwit.com>
Co-authored-by: sahith-narahari <sahithnarahari@gmail.com>

* Refactoring

* Refactoring

* Integrate SignatureV2 API

* Fix wrapper tests

* Fix tests

* Linting and API tweaks

* Update API

* WIP on updating API

* Fix tests

* Update to new SigVerifiableTx

* Rename

* Update docs to reflect ADR 020

* proto-gen

* proto docs

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* Add tests

* Refactor and improving test coverage

* WIP on test coverage

* WIP on test coverage

* proto-gen

* Fix CompactBitArray.Size() bug

* Rename

* Remove Builder interface

* Address review comments

* Update x/auth/tx/sigs.go

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Update x/auth/tx/encoder.go

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Update x/auth/tx/encoder.go

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* Address review feedback

* Fix build issues

* Resolve conflicts

* Fix ValidateBasic test coverage

* Add test for malicious multisig

Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>
Co-authored-by: anilCSE <anil@vitwit.com>
Co-authored-by: sahith-narahari <sahithnarahari@gmail.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
Aaron Craelius
2020-07-06 17:03:45 +00:00
committed by GitHub
co-authored by anilCSE sahith-narahari Federico Kunze atheeshp Alexander Bezobchuk
parent feb69770ef
commit 2f44fbf2ab
56 changed files with 2544 additions and 402 deletions
+37 -35
View File
@@ -7,6 +7,8 @@ import (
"strings"
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/stretchr/testify/require"
@@ -65,9 +67,9 @@ func TestSimulateGasCost(t *testing.T) {
// set up msgs and fee
var tx sdk.Tx
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr3, addr1)
msg3 := types.NewTestMsg(addr2, addr3)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr3, addr1)
msg3 := testdata.NewTestMsg(addr2, addr3)
msgs := []sdk.Msg{msg1, msg2, msg3}
fee := types.NewTestStdFee()
@@ -102,8 +104,8 @@ func TestAnteHandlerSigErrors(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr1, addr3)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr1, addr3)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1, msg2}
@@ -163,7 +165,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg}
@@ -184,8 +186,8 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
checkValidTx(t, anteHandler, ctx, tx, false)
// new tx with another signer and incorrect account numbers
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr2, addr1)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr2, addr1)
msgs = []sdk.Msg{msg1, msg2}
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
@@ -221,7 +223,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg}
@@ -242,8 +244,8 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
checkValidTx(t, anteHandler, ctx, tx, false)
// new tx with another signer and incorrect account numbers
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr2, addr1)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr2, addr1)
msgs = []sdk.Msg{msg1, msg2}
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
@@ -283,7 +285,7 @@ func TestAnteHandlerSequences(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg}
@@ -302,8 +304,8 @@ func TestAnteHandlerSequences(t *testing.T) {
checkValidTx(t, anteHandler, ctx, tx, false)
// new tx with another signer and correct sequences
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr3, addr1)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr3, addr1)
msgs = []sdk.Msg{msg1, msg2}
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{2, 0, 0}
@@ -314,7 +316,7 @@ func TestAnteHandlerSequences(t *testing.T) {
checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized)
// tx from just second signer with incorrect sequence fails
msg = types.NewTestMsg(addr2)
msg = testdata.NewTestMsg(addr2)
msgs = []sdk.Msg{msg}
privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
@@ -325,7 +327,7 @@ func TestAnteHandlerSequences(t *testing.T) {
checkValidTx(t, anteHandler, ctx, tx, false)
// another tx from both of them that passes
msg = types.NewTestMsg(addr1, addr2)
msg = testdata.NewTestMsg(addr1, addr2)
msgs = []sdk.Msg{msg}
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{3, 2}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
@@ -347,7 +349,7 @@ func TestAnteHandlerFees(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg}
@@ -390,7 +392,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
// msg and signatures
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
fee := types.NewStdFee(0, sdk.NewCoins(sdk.NewInt64Coin("atom", 0)))
@@ -441,9 +443,9 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
// set up msgs and fee
var tx sdk.Tx
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr3, addr1)
msg3 := types.NewTestMsg(addr2, addr3)
msg1 := testdata.NewTestMsg(addr1, addr2)
msg2 := testdata.NewTestMsg(addr3, addr1)
msg3 := testdata.NewTestMsg(addr2, addr3)
msgs := []sdk.Msg{msg1, msg2, msg3}
fee := types.NewTestStdFee()
@@ -485,7 +487,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
app.BankKeeper.SetBalances(ctx, addr2, types.NewTestCoins())
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
msgs := []sdk.Msg{msg}
fee := types.NewTestStdFee()
fee2 := types.NewTestStdFee()
@@ -510,12 +512,12 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
msgs []sdk.Msg
err error
}{
{chainID2, 0, 1, fee, msgs, errUnauth}, // test wrong chain_id
{chainID, 0, 2, fee, msgs, errUnauth}, // test wrong seqs
{chainID, 1, 1, fee, msgs, errUnauth}, // test wrong accnum
{chainID, 0, 1, fee, []sdk.Msg{types.NewTestMsg(addr2)}, errUnauth}, // test wrong msg
{chainID, 0, 1, fee2, msgs, errUnauth}, // test wrong fee
{chainID, 0, 1, fee3, msgs, errUnauth}, // test wrong fee
{chainID2, 0, 1, fee, msgs, errUnauth}, // test wrong chain_id
{chainID, 0, 2, fee, msgs, errUnauth}, // test wrong seqs
{chainID, 1, 1, fee, msgs, errUnauth}, // test wrong accnum
{chainID, 0, 1, fee, []sdk.Msg{testdata.NewTestMsg(addr2)}, errUnauth}, // test wrong msg
{chainID, 0, 1, fee2, msgs, errUnauth}, // test wrong fee
{chainID, 0, 1, fee3, msgs, errUnauth}, // test wrong fee
}
privs, seqs = []crypto.PrivKey{priv1}, []uint64{1}
@@ -534,7 +536,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey)
// test wrong signer if public doesn't exist
msg = types.NewTestMsg(addr2)
msg = testdata.NewTestMsg(addr2)
msgs = []sdk.Msg{msg}
privs, accnums, seqs = []crypto.PrivKey{priv1}, []uint64{1}, []uint64{0}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
@@ -564,7 +566,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
var tx sdk.Tx
// test good tx and set public key
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
msgs := []sdk.Msg{msg}
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
fee := types.NewTestStdFee()
@@ -575,7 +577,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
require.Equal(t, acc1.GetPubKey(), priv1.PubKey())
// test public key not found
msg = types.NewTestMsg(addr2)
msg = testdata.NewTestMsg(addr2)
msgs = []sdk.Msg{msg}
tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
sigs := tx.(types.StdTx).Signatures
@@ -693,7 +695,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) {
}
var tx sdk.Tx
msg := types.NewTestMsg(addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8)
msg := testdata.NewTestMsg(addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8)
msgs := []sdk.Msg{msg}
fee := types.NewTestStdFee()
@@ -727,7 +729,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
app.BankKeeper.SetBalances(ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))
var tx sdk.Tx
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg}
@@ -743,7 +745,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
require.NoError(t, app.BankKeeper.SetBalances(ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("atom", 150))))
require.NoError(t, acc2.SetAccountNumber(1))
app.AccountKeeper.SetAccount(ctx, acc2)
msg = types.NewTestMsg(addr2)
msg = testdata.NewTestMsg(addr2)
privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0}
fee = types.NewTestStdFee()
msgs = []sdk.Msg{msg}
@@ -772,7 +774,7 @@ func TestAnteHandlerReCheck(t *testing.T) {
// test that operations skipped on recheck do not run
msg := types.NewTestMsg(addr1)
msg := testdata.NewTestMsg(addr1)
msgs := []sdk.Msg{msg}
fee := types.NewTestStdFee()
+2 -1
View File
@@ -1,6 +1,7 @@
package ante
import (
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/codec/legacy"
@@ -89,7 +90,7 @@ func NewConsumeGasForTxSizeDecorator(ak AccountKeeper) ConsumeTxSizeGasDecorator
}
func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(signing.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}
+5 -3
View File
@@ -5,6 +5,8 @@ import (
"strings"
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
@@ -21,7 +23,7 @@ func TestValidateBasic(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
@@ -58,7 +60,7 @@ func TestValidateMemo(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
@@ -88,7 +90,7 @@ func TestConsumeGasForTxSize(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
+4 -2
View File
@@ -3,6 +3,8 @@ package ante_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
@@ -22,7 +24,7 @@ func TestEnsureMempoolFees(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
@@ -68,7 +70,7 @@ func TestDeductFees(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
+4 -2
View File
@@ -3,6 +3,8 @@ package ante_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
@@ -20,7 +22,7 @@ func TestSetup(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
@@ -52,7 +54,7 @@ func TestRecoverPanic(t *testing.T) {
priv1, _, addr1 := types.KeyTestPubAddr()
// msg and signatures
msg1 := types.NewTestMsg(addr1)
msg1 := testdata.NewTestMsg(addr1)
fee := types.NewTestStdFee()
msgs := []sdk.Msg{msg1}
+7 -17
View File
@@ -9,7 +9,6 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
@@ -24,7 +23,7 @@ var (
simSecp256k1Pubkey secp256k1.PubKeySecp256k1
simSecp256k1Sig [64]byte
_ SigVerifiableTx = (*types.StdTx)(nil) // assert StdTx implements SigVerifiableTx
_ authsigning.SigVerifiableTx = (*types.StdTx)(nil) // assert StdTx implements SigVerifiableTx
)
func init() {
@@ -38,15 +37,6 @@ func init() {
// This is where apps can define their own PubKey
type SignatureVerificationGasConsumer = func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error
// SigVerifiableTx defines a Tx interface for all signature verification decorators
type SigVerifiableTx interface {
sdk.Tx
GetSigners() []sdk.AccAddress
GetPubKeys() []crypto.PubKey // If signer already has pubkey in context, this list will have nil in its place
GetSignatures() [][]byte
GetSignaturesV2() ([]signing.SignatureV2, error)
}
// SetPubKeyDecorator sets PubKeys in context for any signer which does not already have pubkey set
// PubKeys must be set in context for all signers before any other sigverify decorators run
// CONTRACT: Tx must implement SigVerifiableTx interface
@@ -61,7 +51,7 @@ func NewSetPubKeyDecorator(ak AccountKeeper) SetPubKeyDecorator {
}
func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}
@@ -118,7 +108,7 @@ func NewSigGasConsumeDecorator(ak AccountKeeper, sigGasConsumer SignatureVerific
}
func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
@@ -186,7 +176,7 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
@@ -268,7 +258,7 @@ func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator
}
func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
@@ -301,7 +291,7 @@ func NewValidateSigCountDecorator(ak AccountKeeper) ValidateSigCountDecorator {
}
func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(SigVerifiableTx)
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a sigTx")
}
@@ -359,7 +349,7 @@ func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey, params types.Params,
) error {
size := sig.BitArray.Size()
size := sig.BitArray.Count()
sigIndex := 0
for i := 0; i < size; i++ {
+5 -4
View File
@@ -2,6 +2,7 @@ package ante_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"testing"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
@@ -37,7 +38,7 @@ func TestSetPubKey(t *testing.T) {
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)
require.NoError(t, acc.SetAccountNumber(uint64(i)))
app.AccountKeeper.SetAccount(ctx, acc)
msgs[i] = types.NewTestMsg(addr)
msgs[i] = testdata.NewTestMsg(addr)
}
fee := types.NewTestStdFee()
@@ -131,7 +132,7 @@ func TestSigVerification(t *testing.T) {
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)
require.NoError(t, acc.SetAccountNumber(uint64(i)))
app.AccountKeeper.SetAccount(ctx, acc)
msgs[i] = types.NewTestMsg(addr)
msgs[i] = testdata.NewTestMsg(addr)
}
fee := types.NewTestStdFee()
@@ -203,7 +204,7 @@ func runSigDecorators(t *testing.T, params types.Params, _ bool, privs ...crypto
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)
require.NoError(t, acc.SetAccountNumber(uint64(i)))
app.AccountKeeper.SetAccount(ctx, acc)
msgs[i] = types.NewTestMsg(addr)
msgs[i] = testdata.NewTestMsg(addr)
accNums[i] = uint64(i)
seqs[i] = uint64(0)
}
@@ -233,7 +234,7 @@ func TestIncrementSequenceDecorator(t *testing.T) {
require.NoError(t, acc.SetAccountNumber(uint64(50)))
app.AccountKeeper.SetAccount(ctx, acc)
msgs := []sdk.Msg{types.NewTestMsg(addr)}
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
privKeys := []crypto.PrivKey{priv}
accNums := []uint64{app.AccountKeeper.GetAccount(ctx, addr).GetAccountNumber()}
accSeqs := []uint64{app.AccountKeeper.GetAccount(ctx, addr).GetSequence()}
+1 -1
View File
@@ -114,7 +114,7 @@ func printAndValidateSigs(
var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")
for i := 0; i < multiSig.BitArray.Size(); i++ {
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))
+4 -2
View File
@@ -8,6 +8,8 @@ import (
"strings"
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/client"
@@ -195,7 +197,7 @@ malformed
}
func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder) {
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
tx := authtypes.NewStdTx(msgs, authtypes.StdFee{}, []authtypes.StdSignature{}, "")
defaultEncoderBytes, err := expected(tx)
@@ -262,6 +264,6 @@ func makeCodec() *codec.Codec {
sdk.RegisterCodec(cdc)
cryptocodec.RegisterCrypto(cdc)
authtypes.RegisterCodec(cdc)
cdc.RegisterConcrete(sdk.TestMsg{}, "cosmos-sdk/Test", nil)
cdc.RegisterConcrete(testdata.TestMsg{}, "cosmos-sdk/Test", nil)
return cdc
}
+66
View File
@@ -0,0 +1,66 @@
package direct
import (
"fmt"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
sdk "github.com/cosmos/cosmos-sdk/types"
types "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// ProtoTx defines an interface which protobuf transactions must implement for
// signature verification via SignModeDirect
type ProtoTx interface {
// GetBodyBytes returns the raw serialized bytes for TxBody
GetBodyBytes() []byte
// GetBodyBytes returns the raw serialized bytes for AuthInfo
GetAuthInfoBytes() []byte
}
// ModeHandler defines the SIGN_MODE_DIRECT SignModeHandler
type ModeHandler struct{}
var _ signing.SignModeHandler = ModeHandler{}
// DefaultMode implements SignModeHandler.DefaultMode
func (ModeHandler) DefaultMode() signingtypes.SignMode {
return signingtypes.SignMode_SIGN_MODE_DIRECT
}
// Modes implements SignModeHandler.Modes
func (ModeHandler) Modes() []signingtypes.SignMode {
return []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_DIRECT}
}
// GetSignBytes implements SignModeHandler.GetSignBytes
func (ModeHandler) GetSignBytes(mode signingtypes.SignMode, data signing.SignerData, tx sdk.Tx) ([]byte, error) {
if mode != signingtypes.SignMode_SIGN_MODE_DIRECT {
return nil, fmt.Errorf("expected %s, got %s", signingtypes.SignMode_SIGN_MODE_DIRECT, mode)
}
protoTx, ok := tx.(ProtoTx)
if !ok {
return nil, fmt.Errorf("can only get direct sign bytes for a ProtoTx, got %T", tx)
}
bodyBz := protoTx.GetBodyBytes()
authInfoBz := protoTx.GetAuthInfoBytes()
return SignBytes(bodyBz, authInfoBz, data.ChainID, data.AccountNumber, data.AccountSequence)
}
// SignBytes returns the SIGN_MODE_DIRECT sign bytes for the provided TxBody bytes, AuthInfo bytes, chain ID,
// account number and sequence.
func SignBytes(bodyBytes, authInfoBytes []byte, chainID string, accnum, sequence uint64) ([]byte, error) {
signDoc := types.SignDoc{
BodyBytes: bodyBytes,
AuthInfoBytes: authInfoBytes,
ChainId: chainID,
AccountNumber: accnum,
AccountSequence: sequence,
}
return signDoc.Marshal()
}
+139
View File
@@ -0,0 +1,139 @@
package direct_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/x/auth/signing/direct"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/cosmos/cosmos-sdk/codec"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/stretchr/testify/require"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
func TestDirectModeHandler(t *testing.T) {
privKey, pubkey, addr := authtypes.KeyTestPubAddr()
interfaceRegistry := codectypes.NewInterfaceRegistry()
interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{})
marshaler := codec.NewProtoCodec(interfaceRegistry)
pubKeyCdc := std.DefaultPublicKeyCodec{}
txGen := tx.NewTxGenerator(marshaler, pubKeyCdc, tx.DefaultSignModeHandler())
txBuilder := txGen.NewTxBuilder()
memo := "sometestmemo"
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
pk, err := pubKeyCdc.Encode(pubkey)
require.NoError(t, err)
var signerInfo []*txtypes.SignerInfo
signerInfo = append(signerInfo, &txtypes.SignerInfo{
PublicKey: pk,
ModeInfo: &txtypes.ModeInfo{
Sum: &txtypes.ModeInfo_Single_{
Single: &txtypes.ModeInfo_Single{
Mode: signingtypes.SignMode_SIGN_MODE_DIRECT,
},
},
},
})
sigData := &signingtypes.SingleSignatureData{
SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT,
}
sig := signingtypes.SignatureV2{
PubKey: pubkey,
Data: sigData,
}
fee := txtypes.Fee{Amount: sdk.NewCoins(sdk.NewInt64Coin("atom", 150)), GasLimit: 20000}
err = txBuilder.SetMsgs(msgs...)
require.NoError(t, err)
txBuilder.SetMemo(memo)
txBuilder.SetFeeAmount(fee.Amount)
txBuilder.SetGasLimit(fee.GasLimit)
err = txBuilder.SetSignatures(sig)
require.NoError(t, err)
t.Log("verify modes and default-mode")
directModeHandler := direct.ModeHandler{}
require.Equal(t, directModeHandler.DefaultMode(), signingtypes.SignMode_SIGN_MODE_DIRECT)
require.Len(t, directModeHandler.Modes(), 1)
signingData := signing.SignerData{
ChainID: "test-chain",
AccountNumber: 1,
AccountSequence: 1,
}
signBytes, err := directModeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT, signingData, txBuilder.GetTx())
require.NoError(t, err)
require.NotNil(t, signBytes)
authInfo := &txtypes.AuthInfo{
Fee: &fee,
SignerInfos: signerInfo,
}
authInfoBytes := marshaler.MustMarshalBinaryBare(authInfo)
anys := make([]*codectypes.Any, len(msgs))
for i, msg := range msgs {
var err error
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
panic(err)
}
}
txBody := &txtypes.TxBody{
Memo: memo,
Messages: anys,
}
bodyBytes := marshaler.MustMarshalBinaryBare(txBody)
t.Log("verify GetSignBytes with generating sign bytes by marshaling SignDoc")
signDoc := txtypes.SignDoc{
AccountNumber: 1,
AccountSequence: 1,
AuthInfoBytes: authInfoBytes,
BodyBytes: bodyBytes,
ChainId: "test-chain",
}
expectedSignBytes, err := signDoc.Marshal()
require.NoError(t, err)
require.Equal(t, expectedSignBytes, signBytes)
t.Log("verify that setting signature doesn't change sign bytes")
sigData.Signature, err = privKey.Sign(signBytes)
require.NoError(t, err)
err = txBuilder.SetSignatures(sig)
require.NoError(t, err)
signBytes, err = directModeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT, signingData, txBuilder.GetTx())
require.NoError(t, err)
require.Equal(t, expectedSignBytes, signBytes)
t.Log("verify GetSignBytes with false txBody data")
signDoc.BodyBytes = []byte("dfafdasfds")
expectedSignBytes, err = signDoc.Marshal()
require.NoError(t, err)
require.NotEqual(t, expectedSignBytes, signBytes)
}
+24
View File
@@ -0,0 +1,24 @@
package signing
import (
"github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/tendermint/tendermint/crypto"
)
// SigVerifiableTx defines a Tx interface for all signature verification decorators
type SigVerifiableTx interface {
types.Tx
GetSigners() []types.AccAddress
GetPubKeys() []crypto.PubKey // If signer already has pubkey in context, this list will have nil in its place
GetSignatures() [][]byte
GetSignaturesV2() ([]signing.SignatureV2, error)
}
// SigFeeMemoTx defines an interface for transactions that support all standard message, signature,
// fee and memo interfaces.
type SigFeeMemoTx interface {
SigVerifiableTx
types.TxWithMemo
types.FeeTx
}
+5 -3
View File
@@ -3,6 +3,8 @@ package signing_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
@@ -31,7 +33,7 @@ func TestVerifySignature(t *testing.T) {
cdc := codec.New()
sdk.RegisterCodec(cdc)
types.RegisterCodec(cdc)
cdc.RegisterConcrete(sdk.TestMsg{}, "cosmos-sdk/Test", nil)
cdc.RegisterConcrete(testdata.TestMsg{}, "cosmos-sdk/Test", nil)
acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr)
_ = app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
@@ -41,7 +43,7 @@ func TestVerifySignature(t *testing.T) {
acc, err := ante.GetSignerAcc(ctx, app.AccountKeeper, addr)
require.NoError(t, app.BankKeeper.SetBalances(ctx, addr, balances))
msgs := []sdk.Msg{types.NewTestMsg(addr)}
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
fee := types.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
signerData := signing.SignerData{
ChainID: chainId,
@@ -65,7 +67,7 @@ func TestVerifySignature(t *testing.T) {
pkSet := []crypto.PubKey{pubKey, pubKey1}
multisigKey := multisig.NewPubKeyMultisigThreshold(2, pkSet)
multisignature := multisig.NewMultisig(2)
msgs = []sdk.Msg{types.NewTestMsg(addr, addr1)}
msgs = []sdk.Msg{testdata.NewTestMsg(addr, addr1)}
multiSignBytes := types.StdSignBytes(signerData.ChainID, signerData.AccountNumber, signerData.AccountSequence,
fee, msgs, memo)
+317
View File
@@ -0,0 +1,317 @@
package tx
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/auth/signing/direct"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
type builder struct {
tx *tx.Tx
// bodyBz represents the protobuf encoding of TxBody. This should be encoding
// from the client using TxRaw if the tx was decoded from the wire
bodyBz []byte
// authInfoBz represents the protobuf encoding of TxBody. This should be encoding
// from the client using TxRaw if the tx was decoded from the wire
authInfoBz []byte
// pubKeys represents the cached crypto.PubKey's that were set either from tx decoding
// or decoded from AuthInfo when GetPubKey's was called
pubKeys []crypto.PubKey
marshaler codec.Marshaler
pubkeyCodec types.PublicKeyCodec
}
var (
_ authsigning.SigFeeMemoTx = &builder{}
_ client.TxBuilder = &builder{}
_ direct.ProtoTx = &builder{}
)
func newBuilder(marshaler codec.Marshaler, pubkeyCodec types.PublicKeyCodec) *builder {
return &builder{
tx: &tx.Tx{
Body: &tx.TxBody{},
AuthInfo: &tx.AuthInfo{
Fee: &tx.Fee{},
},
},
marshaler: marshaler,
pubkeyCodec: pubkeyCodec,
}
}
func (t *builder) GetMsgs() []sdk.Msg {
anys := t.tx.Body.Messages
res := make([]sdk.Msg, len(anys))
for i, any := range anys {
msg := any.GetCachedValue().(sdk.Msg)
res[i] = msg
}
return res
}
// MaxGasWanted defines the max gas allowed.
const MaxGasWanted = uint64((1 << 63) - 1)
func (t *builder) ValidateBasic() error {
theTx := t.tx
if theTx == nil {
return fmt.Errorf("bad Tx")
}
body := t.tx.Body
if body == nil {
return fmt.Errorf("missing TxBody")
}
authInfo := t.tx.AuthInfo
if authInfo == nil {
return fmt.Errorf("missing AuthInfo")
}
fee := authInfo.Fee
if fee == nil {
return fmt.Errorf("missing fee")
}
if fee.GasLimit > MaxGasWanted {
return sdkerrors.Wrapf(
sdkerrors.ErrInvalidRequest,
"invalid gas supplied; %d > %d", fee.GasLimit, MaxGasWanted,
)
}
if fee.Amount.IsAnyNegative() {
return sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
"invalid fee provided: %s", fee.Amount,
)
}
sigs := theTx.Signatures
if len(sigs) == 0 {
return sdkerrors.ErrNoSignatures
}
if len(sigs) != len(t.GetSigners()) {
return sdkerrors.Wrapf(
sdkerrors.ErrUnauthorized,
"wrong number of signers; expected %d, got %d", t.GetSigners(), len(sigs),
)
}
return nil
}
func (t *builder) GetBodyBytes() []byte {
if len(t.bodyBz) == 0 {
// if bodyBz is empty, then marshal the body. bodyBz will generally
// be set to nil whenever SetBody is called so the result of calling
// this method should always return the correct bytes. Note that after
// decoding bodyBz is derived from TxRaw so that it matches what was
// transmitted over the wire
t.bodyBz = t.marshaler.MustMarshalBinaryBare(t.tx.Body)
}
return t.bodyBz
}
func (t *builder) GetAuthInfoBytes() []byte {
if len(t.authInfoBz) == 0 {
// if authInfoBz is empty, then marshal the body. authInfoBz will generally
// be set to nil whenever SetAuthInfo is called so the result of calling
// this method should always return the correct bytes. Note that after
// decoding authInfoBz is derived from TxRaw so that it matches what was
// transmitted over the wire
t.authInfoBz = t.marshaler.MustMarshalBinaryBare(t.tx.AuthInfo)
}
return t.authInfoBz
}
func (t *builder) GetSigners() []sdk.AccAddress {
var signers []sdk.AccAddress
seen := map[string]bool{}
for _, msg := range t.GetMsgs() {
for _, addr := range msg.GetSigners() {
if !seen[addr.String()] {
signers = append(signers, addr)
seen[addr.String()] = true
}
}
}
return signers
}
func (t *builder) GetPubKeys() []crypto.PubKey {
if t.pubKeys == nil {
signerInfos := t.tx.AuthInfo.SignerInfos
pubKeys := make([]crypto.PubKey, len(signerInfos))
for i, si := range signerInfos {
var err error
pk := si.PublicKey
if pk != nil {
pubKeys[i], err = t.pubkeyCodec.Decode(si.PublicKey)
if err != nil {
panic(err)
}
}
}
t.pubKeys = pubKeys
}
return t.pubKeys
}
func (t *builder) GetGas() uint64 {
return t.tx.AuthInfo.Fee.GasLimit
}
func (t *builder) GetFee() sdk.Coins {
return t.tx.AuthInfo.Fee.Amount
}
func (t *builder) FeePayer() sdk.AccAddress {
return t.GetSigners()[0]
}
func (t *builder) GetMemo() string {
return t.tx.Body.Memo
}
func (t *builder) GetSignatures() [][]byte {
return t.tx.Signatures
}
func (t *builder) GetSignaturesV2() ([]signing.SignatureV2, error) {
signerInfos := t.tx.AuthInfo.SignerInfos
sigs := t.tx.Signatures
pubKeys := t.GetPubKeys()
n := len(signerInfos)
res := make([]signing.SignatureV2, n)
for i, si := range signerInfos {
var err error
sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
if err != nil {
return nil, err
}
res[i] = signing.SignatureV2{
PubKey: pubKeys[i],
Data: sigData,
}
}
return res, nil
}
func (t *builder) SetMsgs(msgs ...sdk.Msg) error {
anys := make([]*codectypes.Any, len(msgs))
for i, msg := range msgs {
var err error
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
return err
}
}
t.tx.Body.Messages = anys
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
t.bodyBz = nil
return nil
}
func (t *builder) SetMemo(memo string) {
t.tx.Body.Memo = memo
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
t.bodyBz = nil
}
func (t *builder) SetGasLimit(limit uint64) {
if t.tx.AuthInfo.Fee == nil {
t.tx.AuthInfo.Fee = &tx.Fee{}
}
t.tx.AuthInfo.Fee.GasLimit = limit
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
t.authInfoBz = nil
}
func (t *builder) SetFeeAmount(coins sdk.Coins) {
if t.tx.AuthInfo.Fee == nil {
t.tx.AuthInfo.Fee = &tx.Fee{}
}
t.tx.AuthInfo.Fee.Amount = coins
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
t.authInfoBz = nil
}
func (t *builder) SetSignatures(signatures ...signing.SignatureV2) error {
n := len(signatures)
signerInfos := make([]*tx.SignerInfo, n)
rawSigs := make([][]byte, n)
for i, sig := range signatures {
var modeInfo *tx.ModeInfo
modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data)
pk, err := t.pubkeyCodec.Encode(sig.PubKey)
if err != nil {
return err
}
signerInfos[i] = &tx.SignerInfo{
PublicKey: pk,
ModeInfo: modeInfo,
}
}
t.setSignerInfos(signerInfos)
t.setSignatures(rawSigs)
return nil
}
func (t *builder) setSignerInfos(infos []*tx.SignerInfo) {
t.tx.AuthInfo.SignerInfos = infos
// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
t.authInfoBz = nil
// set cached pubKeys to nil because they no longer match tx.AuthInfo
t.pubKeys = nil
}
func (t *builder) setSignatures(sigs [][]byte) {
t.tx.Signatures = sigs
}
func (t *builder) GetTx() authsigning.SigFeeMemoTx {
return t
}
+234
View File
@@ -0,0 +1,234 @@
package tx
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
tx2 "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/stretchr/testify/require"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestTxBuilder(t *testing.T) {
_, pubkey, addr := authtypes.KeyTestPubAddr()
marshaler := codec.NewHybridCodec(codec.New(), codectypes.NewInterfaceRegistry())
tx := newBuilder(marshaler, std.DefaultPublicKeyCodec{})
cdc := std.DefaultPublicKeyCodec{}
memo := "sometestmemo"
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
pk, err := cdc.Encode(pubkey)
require.NoError(t, err)
var signerInfo []*tx2.SignerInfo
signerInfo = append(signerInfo, &tx2.SignerInfo{
PublicKey: pk,
ModeInfo: &tx2.ModeInfo{
Sum: &tx2.ModeInfo_Single_{
Single: &tx2.ModeInfo_Single{
Mode: signing.SignMode_SIGN_MODE_DIRECT,
},
},
},
})
var sig signing.SignatureV2
sig = signing.SignatureV2{
PubKey: pubkey,
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: pubkey.Bytes(),
},
}
fee := tx2.Fee{Amount: sdk.NewCoins(sdk.NewInt64Coin("atom", 150)), GasLimit: 20000}
t.Log("verify that authInfo bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from GetAuthInfoBytes")
authInfo := &tx2.AuthInfo{
Fee: &fee,
SignerInfos: signerInfo,
}
authInfoBytes := marshaler.MustMarshalBinaryBare(authInfo)
require.NotEmpty(t, authInfoBytes)
t.Log("verify that body bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from GetBodyBytes")
anys := make([]*codectypes.Any, len(msgs))
for i, msg := range msgs {
var err error
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
panic(err)
}
}
txBody := &tx2.TxBody{
Memo: memo,
Messages: anys,
}
bodyBytes := marshaler.MustMarshalBinaryBare(txBody)
require.NotEmpty(t, bodyBytes)
require.Empty(t, tx.GetBodyBytes())
t.Log("verify that calling the SetMsgs, SetMemo results in the correct GetBodyBytes")
require.NotEqual(t, bodyBytes, tx.GetBodyBytes())
err = tx.SetMsgs(msgs...)
require.NoError(t, err)
require.NotEqual(t, bodyBytes, tx.GetBodyBytes())
tx.SetMemo(memo)
require.Equal(t, bodyBytes, tx.GetBodyBytes())
require.Equal(t, len(msgs), len(tx.GetMsgs()))
require.Equal(t, 0, len(tx.GetPubKeys()))
t.Log("verify that updated AuthInfo results in the correct GetAuthInfoBytes and GetPubKeys")
require.NotEqual(t, authInfoBytes, tx.GetAuthInfoBytes())
tx.SetFeeAmount(fee.Amount)
require.NotEqual(t, authInfoBytes, tx.GetAuthInfoBytes())
tx.SetGasLimit(fee.GasLimit)
require.NotEqual(t, authInfoBytes, tx.GetAuthInfoBytes())
err = tx.SetSignatures(sig)
require.NoError(t, err)
// once fee, gas and signerInfos are all set, AuthInfo bytes should match
require.Equal(t, authInfoBytes, tx.GetAuthInfoBytes())
require.Equal(t, len(msgs), len(tx.GetMsgs()))
require.Equal(t, 1, len(tx.GetPubKeys()))
require.Equal(t, pubkey.Bytes(), tx.GetPubKeys()[0].Bytes())
}
func TestBuilderValidateBasic(t *testing.T) {
// keys and addresses
_, pubKey1, addr1 := authtypes.KeyTestPubAddr()
_, pubKey2, addr2 := authtypes.KeyTestPubAddr()
// msg and signatures
msg1 := testdata.NewTestMsg(addr1, addr2)
fee := authtypes.NewTestStdFee()
msgs := []sdk.Msg{msg1}
// require to fail validation upon invalid fee
badFee := authtypes.NewTestStdFee()
badFee.Amount[0].Amount = sdk.NewInt(-5)
marshaler := codec.NewHybridCodec(codec.New(), codectypes.NewInterfaceRegistry())
bldr := newBuilder(marshaler, std.DefaultPublicKeyCodec{})
var sig1, sig2 signing.SignatureV2
sig1 = signing.SignatureV2{
PubKey: pubKey1,
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: pubKey1.Bytes(),
},
}
sig2 = signing.SignatureV2{
PubKey: pubKey2,
Data: &signing.SingleSignatureData{
SignMode: signing.SignMode_SIGN_MODE_DIRECT,
Signature: pubKey2.Bytes(),
},
}
err := bldr.SetMsgs(msgs...)
require.NoError(t, err)
bldr.SetGasLimit(200000)
err = bldr.SetSignatures(sig1, sig2)
require.NoError(t, err)
bldr.SetFeeAmount(badFee.Amount)
err = bldr.ValidateBasic()
require.Error(t, err)
_, code, _ := sdkerrors.ABCIInfo(err, false)
require.Equal(t, sdkerrors.ErrInsufficientFee.ABCICode(), code)
// require to fail validation when no signatures exist
err = bldr.SetSignatures()
require.NoError(t, err)
bldr.SetFeeAmount(fee.Amount)
err = bldr.ValidateBasic()
require.Error(t, err)
_, code, _ = sdkerrors.ABCIInfo(err, false)
require.Equal(t, sdkerrors.ErrNoSignatures.ABCICode(), code)
// require to fail with nil values for tx, authinfo
err = bldr.SetMsgs(msgs...)
require.NoError(t, err)
err = bldr.ValidateBasic()
require.Error(t, err)
// require to fail validation when signatures do not match expected signers
err = bldr.SetSignatures(sig1)
require.NoError(t, err)
err = bldr.ValidateBasic()
require.Error(t, err)
_, code, _ = sdkerrors.ABCIInfo(err, false)
require.Equal(t, sdkerrors.ErrUnauthorized.ABCICode(), code)
require.Error(t, err)
bldr.SetFeeAmount(fee.Amount)
err = bldr.SetSignatures(sig1, sig2)
require.NoError(t, err)
err = bldr.ValidateBasic()
require.NoError(t, err)
// gas limit too high
bldr.SetGasLimit(MaxGasWanted + 1)
err = bldr.ValidateBasic()
require.Error(t, err)
bldr.SetGasLimit(MaxGasWanted - 1)
err = bldr.ValidateBasic()
require.NoError(t, err)
// bad builder structs
// missing body
body := bldr.tx.Body
bldr.tx.Body = nil
err = bldr.ValidateBasic()
require.Error(t, err)
bldr.tx.Body = body
err = bldr.ValidateBasic()
require.NoError(t, err)
// missing fee
f := bldr.tx.AuthInfo.Fee
bldr.tx.AuthInfo.Fee = nil
err = bldr.ValidateBasic()
require.Error(t, err)
bldr.tx.AuthInfo.Fee = f
err = bldr.ValidateBasic()
require.NoError(t, err)
// missing AuthInfo
authInfo := bldr.tx.AuthInfo
bldr.tx.AuthInfo = nil
err = bldr.ValidateBasic()
require.Error(t, err)
bldr.tx.AuthInfo = authInfo
err = bldr.ValidateBasic()
require.NoError(t, err)
// missing tx
bldr.tx = nil
err = bldr.ValidateBasic()
require.Error(t, err)
}
+82
View File
@@ -0,0 +1,82 @@
package tx
import (
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler and PublicKeyCodec
func DefaultTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, error) {
var raw tx.TxRaw
err := cdc.UnmarshalBinaryBare(txBytes, &raw)
if err != nil {
return nil, err
}
var theTx tx.Tx
err = cdc.UnmarshalBinaryBare(txBytes, &theTx)
if err != nil {
return nil, err
}
pks, err := extractPubKeys(theTx, keyCodec)
if err != nil {
return nil, err
}
return &builder{
tx: &theTx,
bodyBz: raw.BodyBytes,
authInfoBz: raw.AuthInfoBytes,
pubKeys: pks,
marshaler: cdc,
pubkeyCodec: keyCodec,
}, nil
}
}
// DefaultTxDecoder returns a default protobuf JSON TxDecoder using the provided Marshaler and PublicKeyCodec
func DefaultJSONTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, error) {
var theTx tx.Tx
err := cdc.UnmarshalJSON(txBytes, &theTx)
if err != nil {
return nil, err
}
pks, err := extractPubKeys(theTx, keyCodec)
if err != nil {
return nil, err
}
return &builder{
tx: &theTx,
pubKeys: pks,
marshaler: cdc,
pubkeyCodec: keyCodec,
}, nil
}
}
func extractPubKeys(tx tx.Tx, keyCodec cryptotypes.PublicKeyCodec) ([]crypto.PubKey, error) {
if tx.AuthInfo == nil {
return []crypto.PubKey{}, nil
}
signerInfos := tx.AuthInfo.SignerInfos
pks := make([]crypto.PubKey, len(signerInfos))
for i, si := range signerInfos {
pk, err := keyCodec.Decode(si.PublicKey)
if err != nil {
return nil, err
}
pks[i] = pk
}
return pks, nil
}
+39
View File
@@ -0,0 +1,39 @@
package tx
import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
// DefaultTxEncoder returns a default protobuf TxEncoder using the provided Marshaler
func DefaultTxEncoder(marshaler codec.Marshaler) types.TxEncoder {
return func(tx types.Tx) ([]byte, error) {
wrapper, ok := tx.(*builder)
if !ok {
return nil, fmt.Errorf("expected %T, got %T", &builder{}, tx)
}
raw := &txtypes.TxRaw{
BodyBytes: wrapper.GetBodyBytes(),
AuthInfoBytes: wrapper.GetAuthInfoBytes(),
Signatures: wrapper.tx.Signatures,
}
return marshaler.MarshalBinaryBare(raw)
}
}
// DefaultTxEncoder returns a default protobuf JSON TxEncoder using the provided Marshaler
func DefaultJSONTxEncoder(marshaler codec.Marshaler) types.TxEncoder {
return func(tx types.Tx) ([]byte, error) {
wrapper, ok := tx.(*builder)
if !ok {
return nil, fmt.Errorf("expected %T, got %T", &builder{}, tx)
}
return marshaler.MarshalJSON(wrapper.tx)
}
}
+56
View File
@@ -0,0 +1,56 @@
package tx
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)
type generator struct {
marshaler codec.Marshaler
pubkeyCodec types.PublicKeyCodec
handler signing.SignModeHandler
decoder sdk.TxDecoder
encoder sdk.TxEncoder
jsonDecoder sdk.TxDecoder
jsonEncoder sdk.TxEncoder
}
// NewTxGenerator returns a new protobuf TxGenerator using the provided Marshaler, PublicKeyCodec and SignModeHandler.
func NewTxGenerator(marshaler codec.Marshaler, pubkeyCodec types.PublicKeyCodec, signModeHandler signing.SignModeHandler) client.TxGenerator {
return &generator{
marshaler: marshaler,
pubkeyCodec: pubkeyCodec,
handler: signModeHandler,
decoder: DefaultTxDecoder(marshaler, pubkeyCodec),
encoder: DefaultTxEncoder(marshaler),
jsonDecoder: DefaultJSONTxDecoder(marshaler, pubkeyCodec),
jsonEncoder: DefaultJSONTxEncoder(marshaler),
}
}
func (g generator) NewTxBuilder() client.TxBuilder {
return newBuilder(g.marshaler, g.pubkeyCodec)
}
func (g generator) SignModeHandler() signing.SignModeHandler {
return g.handler
}
func (g generator) TxEncoder() sdk.TxEncoder {
return g.encoder
}
func (g generator) TxDecoder() sdk.TxDecoder {
return g.decoder
}
func (g generator) TxJSONEncoder() sdk.TxEncoder {
return g.jsonEncoder
}
func (g generator) TxJSONDecoder() sdk.TxDecoder {
return g.jsonDecoder
}
+25
View File
@@ -0,0 +1,25 @@
package tx
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/testutil"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
)
func TestGenerator(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{})
marshaler := codec.NewProtoCodec(interfaceRegistry)
pubKeyCodec := std.DefaultPublicKeyCodec{}
signModeHandler := DefaultSignModeHandler()
suite.Run(t, testutil.NewTxGeneratorTestSuite(NewTxGenerator(marshaler, pubKeyCodec, signModeHandler)))
}
+20
View File
@@ -0,0 +1,20 @@
package tx
import (
signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/signing/direct"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// DefaultSignModeHandler returns the default protobuf SignModeHandler supporting
// SIGN_MODE_DIRECT and SIGN_MODE_LEGACY_AMINO_JSON.
func DefaultSignModeHandler() signing.SignModeHandler {
return signing.NewSignModeHandlerMap(
signing2.SignMode_SIGN_MODE_DIRECT,
[]signing.SignModeHandler{
authtypes.LegacyAminoJSONHandler{},
direct.ModeHandler{},
},
)
}
+104
View File
@@ -0,0 +1,104 @@
package tx
import (
"fmt"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)
// SignatureDataToModeInfoAndSig converts a SignatureData to a ModeInfo and raw bytes signature
func SignatureDataToModeInfoAndSig(data signing.SignatureData) (*tx.ModeInfo, []byte) {
if data == nil {
return nil, nil
}
switch data := data.(type) {
case *signing.SingleSignatureData:
return &tx.ModeInfo{
Sum: &tx.ModeInfo_Single_{
Single: &tx.ModeInfo_Single{Mode: data.SignMode},
},
}, data.Signature
case *signing.MultiSignatureData:
n := len(data.Signatures)
modeInfos := make([]*tx.ModeInfo, n)
sigs := make([][]byte, n)
for i, d := range data.Signatures {
modeInfos[i], sigs[i] = SignatureDataToModeInfoAndSig(d)
}
multisig := types.MultiSignature{
Signatures: sigs,
}
sig, err := multisig.Marshal()
if err != nil {
panic(err)
}
return &tx.ModeInfo{
Sum: &tx.ModeInfo_Multi_{
Multi: &tx.ModeInfo_Multi{
Bitarray: data.BitArray,
ModeInfos: modeInfos,
},
},
}, sig
default:
panic(fmt.Sprintf("unexpected signature data type %T", data))
}
}
// ModeInfoAndSigToSignatureData converts a ModeInfo and raw bytes signature to a SignatureData or returns
// an error
func ModeInfoAndSigToSignatureData(modeInfo *tx.ModeInfo, sig []byte) (signing.SignatureData, error) {
switch modeInfo := modeInfo.Sum.(type) {
case *tx.ModeInfo_Single_:
return &signing.SingleSignatureData{
SignMode: modeInfo.Single.Mode,
Signature: sig,
}, nil
case *tx.ModeInfo_Multi_:
multi := modeInfo.Multi
sigs, err := decodeMultisignatures(sig)
if err != nil {
return nil, err
}
sigv2s := make([]signing.SignatureData, len(sigs))
for i, mi := range multi.ModeInfos {
sigv2s[i], err = ModeInfoAndSigToSignatureData(mi, sigs[i])
if err != nil {
return nil, err
}
}
return &signing.MultiSignatureData{
BitArray: multi.Bitarray,
Signatures: sigv2s,
}, nil
default:
panic(fmt.Errorf("unexpected ModeInfo data type %T", modeInfo))
}
}
// decodeMultisignatures safely decodes the the raw bytes as a MultiSignature protobuf message
func decodeMultisignatures(bz []byte) ([][]byte, error) {
multisig := types.MultiSignature{}
err := multisig.Unmarshal(bz)
if err != nil {
return nil, err
}
// NOTE: it is import to reject multi-signatures that contain unrecognized fields because this is an exploitable
// malleability in the protobuf message. Basically an attacker could bloat a MultiSignature message with unknown
// fields, thus bloating the transaction and causing it to fail.
if len(multisig.XXX_unrecognized) > 0 {
return nil, fmt.Errorf("rejecting unrecognized fields found in MultiSignature")
}
return multisig.Signatures, nil
}
+40
View File
@@ -0,0 +1,40 @@
package tx
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/codec/testdata"
)
func TestDecodeMultisignatures(t *testing.T) {
testSigs := [][]byte{
[]byte("dummy1"),
[]byte("dummy2"),
[]byte("dummy3"),
}
badMultisig := testdata.BadMultiSignature{
Signatures: testSigs,
MaliciousField: []byte("bad stuff..."),
}
bz, err := badMultisig.Marshal()
require.NoError(t, err)
_, err = decodeMultisignatures(bz)
require.Error(t, err)
goodMultisig := types.MultiSignature{
Signatures: testSigs,
}
bz, err = goodMultisig.Marshal()
require.NoError(t, err)
decodedSigs, err := decodeMultisignatures(bz)
require.NoError(t, err)
require.Equal(t, testSigs, decodedSigs)
}
+1 -1
View File
@@ -20,7 +20,7 @@ type StdTxBuilder struct {
var _ client.TxBuilder = &StdTxBuilder{}
// GetTx implements TxBuilder.GetTx
func (s *StdTxBuilder) GetTx() sdk.Tx {
func (s *StdTxBuilder) GetTx() authsigning.SigFeeMemoTx {
return s.StdTx
}
+3 -1
View File
@@ -3,6 +3,8 @@ package types_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/cosmos/cosmos-sdk/client/testutil"
"github.com/stretchr/testify/suite"
@@ -15,7 +17,7 @@ import (
func testCodec() *codec.Codec {
cdc := codec.New()
sdk.RegisterCodec(cdc)
cdc.RegisterConcrete(sdk.TestMsg{}, "cosmos-sdk/Test", nil)
cdc.RegisterConcrete(&testdata.TestMsg{}, "cosmos-sdk/Test", nil)
return cdc
}
+1 -1
View File
@@ -413,7 +413,7 @@ func pubKeySigToSigData(cdc *codec.Codec, key crypto.PubKey, sig []byte) (signin
sigDatas := make([]signing.SignatureData, len(sigs))
pubKeys := multiPK.GetPubKeys()
bitArray := multiSig.BitArray
n := multiSig.BitArray.Size()
n := multiSig.BitArray.Count()
signatures := multisig.NewMultisig(n)
sigIdx := 0
for i := 0; i < n; i++ {
+8 -6
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
@@ -27,7 +29,7 @@ var (
)
func TestStdTx(t *testing.T) {
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
fee := NewTestStdFee()
sigs := []StdSignature{}
@@ -54,7 +56,7 @@ func TestStdSignBytes(t *testing.T) {
want string
}{
{
args{"1234", 3, 6, defaultFee, []sdk.Msg{sdk.NewTestMsg(addr)}, "memo"},
args{"1234", 3, 6, defaultFee, []sdk.Msg{testdata.NewTestMsg(addr)}, "memo"},
fmt.Sprintf("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"100000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}", addr),
},
}
@@ -72,7 +74,7 @@ func TestTxValidateBasic(t *testing.T) {
priv2, _, addr2 := KeyTestPubAddr()
// msg and signatures
msg1 := NewTestMsg(addr1, addr2)
msg1 := testdata.NewTestMsg(addr1, addr2)
fee := NewTestStdFee()
msgs := []sdk.Msg{msg1}
@@ -127,10 +129,10 @@ func TestDefaultTxEncoder(t *testing.T) {
cdc := codec.New()
sdk.RegisterCodec(cdc)
RegisterCodec(cdc)
cdc.RegisterConcrete(sdk.TestMsg{}, "cosmos-sdk/Test", nil)
cdc.RegisterConcrete(testdata.TestMsg{}, "cosmos-sdk/Test", nil)
encoder := DefaultTxEncoder(cdc)
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
fee := NewTestStdFee()
sigs := []StdSignature{}
@@ -238,7 +240,7 @@ func TestGetSignaturesV2(t *testing.T) {
fee := NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
sig := StdSignature{PubKey: pubKey.Bytes(), Signature: dummy}
stdTx := NewStdTx([]sdk.Msg{NewTestMsg()}, fee, []StdSignature{sig}, "testsigs")
stdTx := NewStdTx([]sdk.Msg{testdata.NewTestMsg()}, fee, []StdSignature{sig}, "testsigs")
sigs, err := stdTx.GetSignaturesV2()
require.Nil(t, err)
-4
View File
@@ -7,10 +7,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
func NewTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
return sdk.NewTestMsg(addrs...)
}
func NewTestStdFee() StdFee {
return NewStdFee(100000,
sdk.NewCoins(sdk.NewInt64Coin("atom", 150)),
+3 -1
View File
@@ -4,6 +4,8 @@ import (
"reflect"
"testing"
"github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
@@ -23,7 +25,7 @@ func TestTxBuilderBuild(t *testing.T) {
Fees sdk.Coins
GasPrices sdk.DecCoins
}
defaultMsg := []sdk.Msg{sdk.NewTestMsg(addr)}
defaultMsg := []sdk.Msg{testdata.NewTestMsg(addr)}
tests := []struct {
name string
fields fields
+4 -2
View File
@@ -4,12 +4,14 @@ import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/codec/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// NewTestMsg generates a test message
func NewTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
return sdk.NewTestMsg(addrs...)
func NewTestMsg(addrs ...sdk.AccAddress) *testdata.TestMsg {
return testdata.NewTestMsg(addrs...)
}
// NewTestCoins coins to more than cover the fee