Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulate SigVerification correctly #5179

Closed
wants to merge 8 commits into from
52 changes: 52 additions & 0 deletions x/auth/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,58 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
require.Equal(t, sdk.CodespaceRoot, result.Codespace)
}

// Test that simulate transaction accurately estimates gas cost
func TestSimulateGasCost(t *testing.T) {
// setup
app, ctx := createTestApp(true)
ctx = ctx.WithBlockHeight(1)
anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer)

// keys and addresses
priv1, _, addr1 := types.KeyTestPubAddr()
priv2, _, addr2 := types.KeyTestPubAddr()
priv3, _, addr3 := types.KeyTestPubAddr()

// set the accounts
acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
acc1.SetCoins(types.NewTestCoins())
require.NoError(t, acc1.SetAccountNumber(0))
app.AccountKeeper.SetAccount(ctx, acc1)
acc2 := app.AccountKeeper.NewAccountWithAddress(ctx, addr2)
acc2.SetCoins(types.NewTestCoins())
require.NoError(t, acc2.SetAccountNumber(1))
app.AccountKeeper.SetAccount(ctx, acc2)
acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3)
acc3.SetCoins(types.NewTestCoins())
require.NoError(t, acc3.SetAccountNumber(2))
app.AccountKeeper.SetAccount(ctx, acc3)

// set up msgs and fee
var tx sdk.Tx
msg1 := types.NewTestMsg(addr1, addr2)
msg2 := types.NewTestMsg(addr3, addr1)
msg3 := types.NewTestMsg(addr2, addr3)
msgs := []sdk.Msg{msg1, msg2, msg3}
fee := types.NewTestStdFee()

// signers in order. accnums are all 0 because it is in genesis block
privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)

cc, _ := ctx.CacheContext()
newCtx, err := anteHandler(cc, tx, true)
require.Nil(t, err, "transaction failed on simulate mode")

simulatedGas := newCtx.GasMeter().GasConsumed()
fee.Gas = simulatedGas

// update tx with simulated gas estimate
tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee)
_, err = anteHandler(ctx, tx, false)

require.Nil(t, err, "transaction failed with gas estimate")
}

// Test various error cases in the AnteHandler control flow.
func TestAnteHandlerSigErrors(t *testing.T) {
// setup
Expand Down
4 changes: 4 additions & 0 deletions x/auth/ante/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
feePayer := feeTx.FeePayer()
feePayerAcc := dfd.ak.GetAccount(ctx, feePayer)

if feePayerAcc == nil {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", feePayer)
}

// deduct the fees
if !feeTx.GetFee().IsZero() {
err = DeductFees(dfd.supplyKeeper, ctx, feePayerAcc, feeTx.GetFee())
Expand Down
32 changes: 22 additions & 10 deletions x/auth/ante/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ func NewSetPubKeyDecorator(ak keeper.AccountKeeper) SetPubKeyDecorator {
}

func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if simulate {
return next(ctx, tx, simulate)
}
sigTx, ok := tx.(SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
Expand All @@ -73,9 +70,14 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b
for i, pk := range pubkeys {
// PublicKey was omitted from slice since it has already been set in context
if pk == nil {
continue
if simulate {
pk = simSecp256k1Pubkey
} else {
continue
}
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
}
if !bytes.Equal(pk.Address(), signers[i]) {
// Only make check if simulate=false
if !simulate && !bytes.Equal(pk.Address(), signers[i]) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey,
"pubKey does not match signer address %s with signer index: %d", signers[i], i)
}
Expand All @@ -84,6 +86,10 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b
if err != nil {
return ctx, err
}
// account already has pubkey set,no need to reset
if acc.GetPubKey() != nil {
continue
}
err = acc.SetPubKey(pk)
if err != nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, err.Error())
Expand Down Expand Up @@ -131,16 +137,22 @@ func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
pubKey := signerAcc.GetPubKey()

if simulate {
// In simulate mode the transaction comes with no signatures, thus if the
// account's pubkey is nil, both signature verification and gasKVStore.Set()
// shall consume the largest amount, i.e. it takes more gas to verify
// secp256k1 keys than ed25519 ones.
if pubKey == nil {
pubKey = simSecp256k1Pubkey
}
// Simulated txs should not contain a signature and are not required to
// contain a pubkey, so we must account for tx size of including a
// StdSignature (Amino encoding) and simulate gas consumption
// (assuming a SECP256k1 simulation key).
consumeSimSigGas(ctx.GasMeter(), pubKey, sig, params)
} else {
err = sgcd.sigGasConsumer(ctx.GasMeter(), sig, pubKey, params)
if err != nil {
return ctx, err
}
}
err = sgcd.sigGasConsumer(ctx.GasMeter(), sig, pubKey, params)
if err != nil {
return ctx, err
}
}

Expand Down