Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions app/ante/cosmos_checktx.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,17 +400,22 @@ func CheckSignatures(ctx sdk.Context, txConfig client.TxConfig, tx sdk.Tx, signe
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
}
var events sdk.Events
// CheckTx and ReCheckTx discard these events (see CosmosCheckTxAnte); building them
// still runs SignatureDataToBz + base64 per signer — measurable CPU/alloc on hot path.
skipSigEvents := ctx.IsCheckTx() || ctx.IsReCheckTx()
for i, sig := range sigs {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signerAddrs[i], sig.Sequence)),
))
if sigBzs, err := authante.SignatureDataToBz(sig.Data); err != nil {
return nil, err
} else {
for _, sigBz := range sigBzs {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)),
))
if !skipSigEvents {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signerAddrs[i], sig.Sequence)),
))
if sigBzs, err := authante.SignatureDataToBz(sig.Data); err != nil {
return nil, err
} else {
for _, sigBz := range sigBzs {
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)),
))
}
}
}

Expand Down
82 changes: 82 additions & 0 deletions app/cosmos_checktx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package app_test

import (
"testing"
"time"

"github.com/sei-protocol/sei-chain/app"
anteante "github.com/sei-protocol/sei-chain/app/ante"
"github.com/sei-protocol/sei-chain/sei-cosmos/client/tx"
"github.com/sei-protocol/sei-chain/sei-cosmos/testutil/testdata"
sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
"github.com/sei-protocol/sei-chain/sei-cosmos/types/tx/signing"
authsigning "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/signing"
authtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/types"
tmproto "github.com/sei-protocol/sei-chain/sei-tendermint/proto/tendermint/types"
"github.com/stretchr/testify/require"
)

// TestCheckSignaturesSkipsEventsOnCheckTx verifies that signature events
// (account sequence + signature bytes) are not built during CheckTx or
// ReCheckTx, but are built during DeliverTx.
func TestCheckSignaturesSkipsEventsOnCheckTx(t *testing.T) {
testApp := app.Setup(t, false, false, false)
ctx := testApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "sei-test", Time: time.Now().UTC()})

encodingConfig := app.MakeEncodingConfig()
txConfig := encodingConfig.TxConfig

privKey, pubKey, addr := testdata.KeyTestPubAddr()

acc := authtypes.NewBaseAccount(addr, pubKey, 0, 0)
signerAccounts := []authtypes.AccountI{acc}
authParams := authtypes.DefaultParams()

// Build and sign a tx.
txBuilder := txConfig.NewTxBuilder()
err := txBuilder.SetMsgs(testdata.NewTestMsg(addr))
require.NoError(t, err)
txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
txBuilder.SetGasLimit(testdata.NewTestGasLimit())

// First pass: set empty sigs so signer info is populated.
sigsV2 := []signing.SignatureV2{{
PubKey: pubKey,
Data: &signing.SingleSignatureData{
SignMode: txConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: 0,
}}
require.NoError(t, txBuilder.SetSignatures(sigsV2...))

// Second pass: real signature.
signerData := authsigning.SignerData{ChainID: "sei-test", AccountNumber: 0, Sequence: 0}
sigV2, err := tx.SignWithPrivKey(txConfig.SignModeHandler().DefaultMode(), signerData, txBuilder, privKey, txConfig, 0)
require.NoError(t, err)
require.NoError(t, txBuilder.SetSignatures(sigV2))

signedTx := txBuilder.GetTx()

// Use an infinite gas meter so signature verification gas consumption doesn't
// cause a panic when the context has no real store behind it.
gasCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter(1, 1))

// DeliverTx context: both flags false → events must be populated.
deliverCtx := gasCtx.WithIsCheckTx(false)
events, err := anteante.CheckSignatures(deliverCtx, txConfig, signedTx, signerAccounts, authParams)
require.NoError(t, err)
require.NotEmpty(t, events, "expected signature events in DeliverTx context")

// CheckTx context → events must be empty.
checkCtx := gasCtx.WithIsCheckTx(true)
events, err = anteante.CheckSignatures(checkCtx, txConfig, signedTx, signerAccounts, authParams)
require.NoError(t, err)
require.Empty(t, events, "expected no signature events in CheckTx context")

// ReCheckTx context → events must be empty.
recheckCtx := gasCtx.WithIsCheckTx(false).WithIsReCheckTx(true)
events, err = anteante.CheckSignatures(recheckCtx, txConfig, signedTx, signerAccounts, authParams)
require.NoError(t, err)
require.Empty(t, events, "expected no signature events in ReCheckTx context")
}
Loading