diff --git a/.github/mergify.yml b/.github/mergify.yml index 336a45f9b7..c78c248ae8 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -2,7 +2,7 @@ pull_request_rules: - name: backport patches to v1.x branch conditions: - base=main - - label=S:backport:v1.x + - label=backport:v1.x actions: backport: branches: diff --git a/.github/workflows/docker-build-publish.yml b/.github/workflows/docker-build-publish.yml index 1c0abb9d18..5d5e63b623 100644 --- a/.github/workflows/docker-build-publish.yml +++ b/.github/workflows/docker-build-publish.yml @@ -28,3 +28,4 @@ jobs: uses: celestiaorg/.github/.github/workflows/reusable_dockerfile_pipeline.yml@v0.2.2 with: dockerfile: docker/Dockerfile_txsim + packageName: txsim diff --git a/app/errors/errors.go b/app/errors/insufficient_gas_price.go similarity index 100% rename from app/errors/errors.go rename to app/errors/insufficient_gas_price.go diff --git a/app/errors/errors_test.go b/app/errors/insufficient_gas_price_test.go similarity index 100% rename from app/errors/errors_test.go rename to app/errors/insufficient_gas_price_test.go diff --git a/app/errors/nonce_mismatch.go b/app/errors/nonce_mismatch.go new file mode 100644 index 0000000000..2726d61060 --- /dev/null +++ b/app/errors/nonce_mismatch.go @@ -0,0 +1,30 @@ +package errors + +import ( + "errors" + "fmt" + "strconv" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// IsNonceMismatch checks if the error is due to a sequence mismatch. +func IsNonceMismatch(err error) bool { + return errors.Is(err, sdkerrors.ErrWrongSequence) +} + +// ParseNonceMismatch extracts the expected sequence number from the +// ErrWrongSequence error. +func ParseNonceMismatch(err error) (uint64, error) { + if !IsNonceMismatch(err) { + return 0, errors.New("error is not a sequence mismatch") + } + + numbers := regexpInt.FindAllString(err.Error(), -1) + if len(numbers) != 2 { + return 0, fmt.Errorf("unexpected wrong sequence error: %w", err) + } + + // the first number is the expected sequence number + return strconv.ParseUint(numbers[0], 10, 64) +} diff --git a/app/errors/nonce_mismatch_test.go b/app/errors/nonce_mismatch_test.go new file mode 100644 index 0000000000..b6509df3a0 --- /dev/null +++ b/app/errors/nonce_mismatch_test.go @@ -0,0 +1,56 @@ +package errors_test + +import ( + "fmt" + "testing" + + "github.com/celestiaorg/celestia-app/app" + "github.com/celestiaorg/celestia-app/app/encoding" + apperr "github.com/celestiaorg/celestia-app/app/errors" + "github.com/celestiaorg/celestia-app/pkg/appconsts" + "github.com/celestiaorg/celestia-app/pkg/namespace" + testutil "github.com/celestiaorg/celestia-app/test/util" + blob "github.com/celestiaorg/celestia-app/x/blob/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +// This will detect any changes to the DeductFeeDecorator which may cause a +// different error message that does not match the regexp. +func TestNonceMismatchIntegration(t *testing.T) { + account := "test" + testApp, kr := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams(), account) + encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) + minGasPrice, err := sdk.ParseDecCoins(fmt.Sprintf("%v%s", appconsts.DefaultMinGasPrice, app.BondDenom)) + require.NoError(t, err) + ctx := testApp.NewContext(true, tmproto.Header{}).WithMinGasPrices(minGasPrice) + signer := blob.NewKeyringSigner(kr, account, testutil.ChainID) + // set the sequence to an incorrect value + signer.SetSequence(2) + builder := signer.NewTxBuilder() + + address, err := signer.GetSignerInfo().GetAddress() + require.NoError(t, err) + + b, err := blob.NewBlob(namespace.RandomNamespace(), []byte("hello world"), 0) + require.NoError(t, err) + + pfb, err := blob.NewMsgPayForBlobs(address.String(), b) + require.NoError(t, err, address) + + tx, err := signer.BuildSignedTx(builder, pfb) + require.NoError(t, err) + + decorator := ante.NewSigVerificationDecorator(testApp.AccountKeeper, encCfg.TxConfig.SignModeHandler()) + anteHandler := sdk.ChainAnteDecorators(decorator) + + // We set simulate to true here to bypass having to initialize the + // accounts public key. + _, err = anteHandler(ctx, tx, true) + require.True(t, apperr.IsNonceMismatch(err), err) + expectedNonce, err := apperr.ParseNonceMismatch(err) + require.NoError(t, err) + require.EqualValues(t, 0, expectedNonce, err) +} diff --git a/app/test/integration_test.go b/app/test/integration_test.go index 585c1b3347..fe340dc4f5 100644 --- a/app/test/integration_test.go +++ b/app/test/integration_test.go @@ -93,15 +93,15 @@ func (s *IntegrationTestSuite) TestMaxBlockSize() { } // Tendermint's default tx size limit is 1 MiB, so we get close to that by - // generating transactions of size 600 KiB because 3 blobs per transaction * - // 200,000 bytes each = 600,000 total bytes = 600 KiB per transaction. + // generating transactions of size 600 KB because 3 blobs per transaction * + // 200,000 bytes each = 600,000 total bytes = 600 KB per transaction. randMultiBlob1MbTxGen := func(c client.Context) []coretypes.Tx { return blobfactory.RandBlobTxsWithAccounts( s.ecfg.TxConfig.TxEncoder(), tmrand.NewRand(), s.cctx.Keyring, c.GRPCClient, - 200000, // 200 KiB + 200000, // 200 KB 3, false, s.cctx.ChainID, @@ -109,7 +109,7 @@ func (s *IntegrationTestSuite) TestMaxBlockSize() { ) } - // Generate 80 randomly sized txs (max size == 50 KiB). Generate these + // Generate 80 randomly sized txs (max size == 50 KB). Generate these // transactions using some of the same accounts as the previous generator to // ensure that the sequence number is being utilized correctly in blob // txs diff --git a/test/txsim/account.go b/test/txsim/account.go index 2634382fe7..99e63fc78b 100644 --- a/test/txsim/account.go +++ b/test/txsim/account.go @@ -3,6 +3,7 @@ package txsim import ( "context" "fmt" + "math" "strings" "sync" @@ -183,9 +184,9 @@ func (am *AccountManager) Submit(ctx context.Context, op Operation) error { } else { builder.SetGasLimit(op.GasLimit) if op.GasPrice > 0 { - builder.SetFeeAmount(types.NewCoins(types.NewInt64Coin(app.BondDenom, int64(float64(op.GasLimit)*op.GasPrice)))) + builder.SetFeeAmount(types.NewCoins(types.NewInt64Coin(app.BondDenom, int64(math.Ceil(float64(op.GasLimit)*op.GasPrice))))) } else { - builder.SetFeeAmount(types.NewCoins(types.NewInt64Coin(app.BondDenom, int64(float64(op.GasLimit)*appconsts.DefaultMinGasPrice)))) + builder.SetFeeAmount(types.NewCoins(types.NewInt64Coin(app.BondDenom, int64(math.Ceil(float64(op.GasLimit)*appconsts.DefaultMinGasPrice))))) } }