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:
co-authored by
anilCSE
sahith-narahari
Federico Kunze
atheeshp
Alexander Bezobchuk
parent
feb69770ef
commit
2f44fbf2ab
+37
-35
@@ -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()
|
||||
|
||||
|
||||
@@ -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,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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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++ {
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)))
|
||||
}
|
||||
@@ -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{},
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,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
|
||||
}
|
||||
|
||||
|
||||
@@ -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++ {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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,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
|
||||
|
||||
Reference in New Issue
Block a user