Skip to content

Commit

Permalink
fix(client/tx): simulate with correct pk (#18472)
Browse files Browse the repository at this point in the history
(cherry picked from commit 80e0c63)

# Conflicts:
#	CHANGELOG.md
#	client/tx/aux_builder_test.go
#	client/tx/factory_test.go
#	client/tx/tx_test.go
  • Loading branch information
JulianToledano authored and mergify[bot] committed Nov 17, 2023
1 parent 03d578b commit 39f9722
Show file tree
Hide file tree
Showing 6 changed files with 663 additions and 27 deletions.
511 changes: 511 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions client/tx/aux_builder_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package tx_test
package tx

import (
"testing"

"github.com/stretchr/testify/require"

<<<<<<< HEAD

Check failure on line 8 in client/tx/aux_builder_test.go

View workflow job for this annotation

GitHub Actions / dependency-review

missing import path

Check failure on line 8 in client/tx/aux_builder_test.go

View workflow job for this annotation

GitHub Actions / dependency-review

missing import path

Check failure on line 8 in client/tx/aux_builder_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

expected 'STRING', found '<<' (typecheck)

Check failure on line 8 in client/tx/aux_builder_test.go

View workflow job for this annotation

GitHub Actions / split-test-files

expected 'STRING', found '<<'
_ "cosmossdk.io/api/cosmos/bank/v1beta1"
"cosmossdk.io/depinject"
clienttestutil "github.com/cosmos/cosmos-sdk/client/testutil"
"github.com/cosmos/cosmos-sdk/client/tx"
=======
>>>>>>> 80e0c631c (fix(client/tx): simulate with correct pk (#18472))
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
Expand All @@ -32,7 +35,7 @@ func TestAuxTxBuilder(t *testing.T) {
// required for test case: "GetAuxSignerData works for DIRECT_AUX"
bankModule.RegisterInterfaces(reg)

var b tx.AuxTxBuilder
var b AuxTxBuilder

testcases := []struct {
name string
Expand Down Expand Up @@ -225,7 +228,7 @@ func TestAuxTxBuilder(t *testing.T) {
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
b = tx.NewAuxTxBuilder()
b = NewAuxTxBuilder()
err := tc.malleate()

if tc.expErr {
Expand Down
40 changes: 29 additions & 11 deletions client/tx/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -34,6 +35,7 @@ type Factory struct {
timeoutHeight uint64
gasAdjustment float64
chainID string
fromName string
offline bool
generateOnly bool
memo string
Expand Down Expand Up @@ -86,6 +88,7 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
accountRetriever: clientCtx.AccountRetriever,
keybase: clientCtx.Keyring,
chainID: clientCtx.ChainID,
fromName: clientCtx.FromName,
offline: clientCtx.Offline,
generateOnly: clientCtx.GenerateOnly,
gas: gasSetting.Gas,
Expand Down Expand Up @@ -414,10 +417,8 @@ func (f Factory) BuildSimTx(msgs ...sdk.Msg) ([]byte, error) {
// Create an empty signature literal as the ante handler will populate with a
// sentinel pubkey.
sig := signing.SignatureV2{
PubKey: pk,
Data: &signing.SingleSignatureData{
SignMode: f.signMode,
},
PubKey: pk,
Data: f.getSimSignatureData(pk),
Sequence: f.Sequence(),
}
if err := txb.SetSignatures(sig); err != nil {
Expand All @@ -438,16 +439,13 @@ func (f Factory) getSimPK() (cryptotypes.PubKey, error) {
pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type
)

// Use the first element from the list of keys in order to generate a valid
// pubkey that supports multiple algorithms.
if f.simulateAndExecute && f.keybase != nil {
records, _ := f.keybase.List()
if len(records) == 0 {
return nil, errors.New("cannot build signature for simulation, key records slice is empty")
record, err := f.keybase.Key(f.fromName)
if err != nil {
return nil, err
}

// take the first record just for simulation purposes
pk, ok = records[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
pk, ok = record.PubKey.GetCachedValue().(cryptotypes.PubKey)
if !ok {
return nil, errors.New("cannot build signature for simulation, failed to convert proto Any to public key")
}
Expand All @@ -456,6 +454,26 @@ func (f Factory) getSimPK() (cryptotypes.PubKey, error) {
return pk, nil
}

// getSimSignatureData based on the pubKey type gets the correct SignatureData type
// to use for building a simulation tx.
func (f Factory) getSimSignatureData(pk cryptotypes.PubKey) signing.SignatureData {
multisigPubKey, ok := pk.(*multisig.LegacyAminoPubKey)
if !ok {
return &signing.SingleSignatureData{SignMode: f.signMode}
}

multiSignatureData := make([]signing.SignatureData, 0, multisigPubKey.Threshold)
for i := uint32(0); i < multisigPubKey.Threshold; i++ {
multiSignatureData = append(multiSignatureData, &signing.SingleSignatureData{
SignMode: f.SignMode(),
})
}

return &signing.MultiSignatureData{
Signatures: multiSignatureData,
}
}

// Prepare ensures the account defined by ctx.GetFromAddress() exists and
// if the account number and/or the account sequence number are zero (not set),
// they will be queried for and set on the provided Factory.
Expand Down
98 changes: 93 additions & 5 deletions client/tx/factory_test.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,122 @@
package tx_test
package tx

import (
"testing"

"github.com/cosmos/cosmos-sdk/client"
<<<<<<< HEAD
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/stretchr/testify/require"
=======
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
>>>>>>> 80e0c631c (fix(client/tx): simulate with correct pk (#18472))
)

func TestFactoryPrepate(t *testing.T) {
func TestFactoryPrepare(t *testing.T) {
t.Parallel()

factory := tx.Factory{}
factory := Factory{}
clientCtx := client.Context{}

output, err := factory.Prepare(clientCtx.WithOffline(true))
require.NoError(t, err)
require.Equal(t, output, factory)

factory = tx.Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1}).WithAccountNumber(5)
factory = Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1}).WithAccountNumber(5)
output, err = factory.Prepare(clientCtx.WithFrom("foo"))
require.NoError(t, err)
require.NotEqual(t, output, factory)
require.Equal(t, output.AccountNumber(), uint64(5))
require.Equal(t, output.Sequence(), uint64(1))

factory = tx.Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1})
factory = Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1})
output, err = factory.Prepare(clientCtx.WithFrom("foo"))
require.NoError(t, err)
require.NotEqual(t, output, factory)
require.Equal(t, output.AccountNumber(), uint64(10))
require.Equal(t, output.Sequence(), uint64(1))
}

func TestFactory_getSimPKType(t *testing.T) {
// setup keyring
registry := codectypes.NewInterfaceRegistry()
cryptocodec.RegisterInterfaces(registry)
k := keyring.NewInMemory(codec.NewProtoCodec(registry))

tests := []struct {
name string
fromName string
genKey func(fromName string, k keyring.Keyring) error
wantType types.PubKey
}{
{
name: "simple key",
fromName: "testKey",
genKey: func(fromName string, k keyring.Keyring) error {
_, err := k.NewAccount(fromName, testdata.TestMnemonic, "", "", hd.Secp256k1)
return err
},
wantType: (*secp256k1.PubKey)(nil),
},
{
name: "multisig key",
fromName: "multiKey",
genKey: func(fromName string, k keyring.Keyring) error {
pk := multisig.NewLegacyAminoPubKey(1, []types.PubKey{&multisig.LegacyAminoPubKey{}})
_, err := k.SaveMultisig(fromName, pk)
return err
},
wantType: (*multisig.LegacyAminoPubKey)(nil),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.genKey(tt.fromName, k)
require.NoError(t, err)
f := Factory{
keybase: k,
fromName: tt.fromName,
simulateAndExecute: true,
}
got, err := f.getSimPK()
require.NoError(t, err)
require.IsType(t, tt.wantType, got)
})
}
}

func TestFactory_getSimSignatureData(t *testing.T) {
tests := []struct {
name string
pk types.PubKey
wantType any
}{
{
name: "simple pubkey",
pk: &secp256k1.PubKey{},
wantType: (*signing.SingleSignatureData)(nil),
},
{
name: "multisig pubkey",
pk: &multisig.LegacyAminoPubKey{},
wantType: (*signing.MultiSignatureData)(nil),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Factory{}.getSimSignatureData(tt.pk)
require.IsType(t, tt.wantType, got)
})
}
}
2 changes: 1 addition & 1 deletion client/tx/legacy_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tx_test
package tx

import (
"testing"
Expand Down
30 changes: 23 additions & 7 deletions client/tx/tx_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tx_test
package tx

import (
gocontext "context"
Expand All @@ -9,11 +9,19 @@ import (
"github.com/stretchr/testify/require"
"google.golang.org/grpc"

<<<<<<< HEAD
"cosmossdk.io/depinject"

"github.com/cosmos/cosmos-sdk/client"
clienttestutil "github.com/cosmos/cosmos-sdk/client/testutil"
"github.com/cosmos/cosmos-sdk/client/tx"
=======
"cosmossdk.io/x/auth/ante"
"cosmossdk.io/x/auth/signing"
authtx "cosmossdk.io/x/auth/tx"

"github.com/cosmos/cosmos-sdk/client"
>>>>>>> 80e0c631c (fix(client/tx): simulate with correct pk (#18472))
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
Expand Down Expand Up @@ -86,7 +94,7 @@ func TestCalculateGas(t *testing.T) {
stc := tc
txCfg, _ := newTestTxConfig(t)

txf := tx.Factory{}.
txf := Factory{}.
WithChainID("test-chain").
WithTxConfig(txCfg).WithSignMode(txCfg.SignModeHandler().DefaultMode())

Expand All @@ -95,7 +103,7 @@ func TestCalculateGas(t *testing.T) {
gasUsed: tc.args.mockGasUsed,
wantErr: tc.args.mockWantErr,
}
simRes, gotAdjusted, err := tx.CalculateGas(mockClientCtx, txf.WithGasAdjustment(stc.args.adjustment))
simRes, gotAdjusted, err := CalculateGas(mockClientCtx, txf.WithGasAdjustment(stc.args.adjustment))
if stc.expPass {
require.NoError(t, err)
require.Equal(t, simRes.GasInfo.GasUsed, stc.wantEstimate)
Expand All @@ -109,8 +117,8 @@ func TestCalculateGas(t *testing.T) {
}
}

func mockTxFactory(txCfg client.TxConfig) tx.Factory {
return tx.Factory{}.
func mockTxFactory(txCfg client.TxConfig) Factory {
return Factory{}.
WithTxConfig(txCfg).
WithAccountNumber(50).
WithSequence(23).
Expand Down Expand Up @@ -198,7 +206,7 @@ func TestMnemonicInMemo(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
txf := tx.Factory{}.
txf := Factory{}.
WithTxConfig(txConfig).
WithAccountNumber(50).
WithSequence(23).
Expand Down Expand Up @@ -269,7 +277,7 @@ func TestSign(t *testing.T) {

testCases := []struct {
name string
txf tx.Factory
txf Factory
txb client.TxBuilder
from string
overwrite bool
Expand Down Expand Up @@ -356,7 +364,11 @@ func TestSign(t *testing.T) {
var prevSigs []signingtypes.SignatureV2
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
<<<<<<< HEAD
err = tx.Sign(tc.txf, tc.from, tc.txb, tc.overwrite)
=======
err = Sign(context.TODO(), tc.txf, tc.from, tc.txb, tc.overwrite)
>>>>>>> 80e0c631c (fix(client/tx): simulate with correct pk (#18472))
if len(tc.expectedPKs) == 0 {
requireT.Error(err)
} else {
Expand Down Expand Up @@ -420,7 +432,11 @@ func TestPreprocessHook(t *testing.T) {
msg2 := banktypes.NewMsgSend(addr2, sdk.AccAddress("to"), nil)
txb, err := txfDirect.BuildUnsignedTx(msg1, msg2)

<<<<<<< HEAD
err = tx.Sign(txfDirect, from, txb, false)
=======
err = Sign(context.TODO(), txfDirect, from, txb, false)
>>>>>>> 80e0c631c (fix(client/tx): simulate with correct pk (#18472))
requireT.NoError(err)

// Run preprocessing
Expand Down

0 comments on commit 39f9722

Please sign in to comment.