From d11034c8e00a362b5d54b54f13b6129943d8eb05 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Mon, 13 Jul 2026 23:59:16 +0800 Subject: [PATCH 1/2] Use DBImpl for giga mock balance validation --- app/app.go | 32 +++++++++++++++----------- giga/deps/xevm/state/balance.go | 7 ++++++ giga/tests/giga_mock_balances_test.go | 33 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 giga/tests/giga_mock_balances_test.go diff --git a/app/app.go b/app/app.go index a54473a593..be4f10cfcf 100644 --- a/app/app.go +++ b/app/app.go @@ -2016,13 +2016,17 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE }, nil } + // Prepare context for EVM transaction (set infinite gas meter like original flow) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + _, isAssociated := app.GigaEvmKeeper.GetEVMAddress(ctx, seiAddr) - // Run validation checks (fee/nonce/balance - stateless checks done earlier) - validation := app.validateGigaEVMTx(ctx, ethTx, sender, seiAddr, isAssociated) + // Create state DB before validation so balance checks use DBImpl hooks. + stateDB := gigaevmstate.NewDBImpl(ctx, &app.GigaEvmKeeper, false) + defer stateDB.Cleanup() - // Prepare context for EVM transaction (set infinite gas meter like original flow) - ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + // Run validation checks (fee/nonce/balance - stateless checks done earlier) + validation := app.validateGigaEVMTx(ctx, stateDB, ethTx, sender, seiAddr, isAssociated) if validation.err != nil { // Validation failed - bump nonce via keeper if it was valid (matches V2's DeliverTxCallback @@ -2046,10 +2050,6 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE return nil, gigaprecompiles.ErrBalanceMigrationRequired } - // Create state DB for this transaction (only for valid transactions) - stateDB := gigaevmstate.NewDBImpl(ctx, &app.GigaEvmKeeper, false) - defer stateDB.Cleanup() - // Pre-charge gas fee (like V2's ante handler), then execute with feeAlreadyCharged=true. // V2 charges fees in the ante handler, then runs the EVM with feeAlreadyCharged=true // which skips buyGas/refundGas/coinbase. Without this, GasUsed differs between Giga @@ -3025,6 +3025,7 @@ type gigaValidationResult struct { // 7. Balance check func (app *App) validateGigaEVMTx( ctx sdk.Context, + stateDB *gigaevmstate.DBImpl, ethTx *ethtypes.Transaction, sender common.Address, seiAddr sdk.AccAddress, @@ -3199,13 +3200,18 @@ func (app *App) validateGigaEVMTx( balanceCheck := new(big.Int).Mul(new(big.Int).SetUint64(ethTx.Gas()), ethTx.GasFeeCap()) balanceCheck.Add(balanceCheck, ethTx.Value()) - senderBalance := app.GigaEvmKeeper.GetBalance(ctx, seiAddr) + // Route validation balance handling through DBImpl so mock_balances can top + // up the sender via ensureSufficientBalance before the manual precheck. + stateDB.EnsureSufficientBalance(sender, balanceCheck) + senderBalance := stateDB.GetBalance(sender).ToBig() - // Include cast address balance for unassociated addresses (matches V2 PreprocessDecorator) + // Include the derived Sei address balance for unassociated addresses (matches V2 PreprocessDecorator). if !isAssociated { - castAddr := sdk.AccAddress(sender[:]) - castBalance := app.GigaEvmKeeper.GetBalance(ctx, castAddr) - senderBalance = new(big.Int).Add(senderBalance, castBalance) + seiEVMAddr := common.BytesToAddress(seiAddr) + if seiEVMAddr != sender { + seiBalance := stateDB.GetBalance(seiEVMAddr).ToBig() + senderBalance = new(big.Int).Add(senderBalance, seiBalance) + } } if senderBalance.Cmp(balanceCheck) < 0 { diff --git a/giga/deps/xevm/state/balance.go b/giga/deps/xevm/state/balance.go index 2a7c1734ed..9d31ade609 100644 --- a/giga/deps/xevm/state/balance.go +++ b/giga/deps/xevm/state/balance.go @@ -12,6 +12,13 @@ import ( var ZeroInt = uint256.NewInt(0) +func (s *DBImpl) EnsureSufficientBalance(evmAddr common.Address, amt *big.Int) { + if amt == nil || amt.Sign() <= 0 { + return + } + s.ensureSufficientBalance(evmAddr, amt) +} + func (s *DBImpl) SubBalance(evmAddr common.Address, amtUint256 *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int { amt := amtUint256.ToBig() if amt.Sign() == 0 { diff --git a/giga/tests/giga_mock_balances_test.go b/giga/tests/giga_mock_balances_test.go new file mode 100644 index 0000000000..e191255714 --- /dev/null +++ b/giga/tests/giga_mock_balances_test.go @@ -0,0 +1,33 @@ +//go:build mock_balances + +package giga_test + +import ( + "math/big" + "testing" + "time" + + gigaevmstate "github.com/sei-protocol/sei-chain/giga/deps/xevm/state" + "github.com/sei-protocol/sei-chain/occ_tests/utils" + "github.com/stretchr/testify/require" +) + +func TestGigaMockBalancesValidationUsesDBImpl(t *testing.T) { + blockTime := time.Now() + accts := utils.NewTestAccounts(3) + signer := utils.NewSigner() + recipient := utils.NewSigner() + + gigaCtx := NewGigaTestContext(t, accts, blockTime, 1, ModeGigaSequential) + gigaCtx.TestApp.GigaEvmKeeper.SetAddressMapping(gigaCtx.Ctx, signer.AccountAddress, signer.EvmAddress) + + to := recipient.EvmAddress + value := new(big.Int).Mul(gigaevmstate.TopOffAmount, big.NewInt(2)) + fee := big.NewInt(100000000000) + tx := createCustomEVMTx(t, gigaCtx, signer, &to, value, 21000, fee, fee, 0) + + _, results, err := RunBlock(t, gigaCtx, [][]byte{tx}) + require.NoError(t, err) + require.Len(t, results, 1) + require.Equal(t, uint32(0), results[0].Code, results[0].Log) +} From 4d657fe9219d1bd8d8f4a482351810291e3dfe68 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Tue, 14 Jul 2026 12:02:13 +0800 Subject: [PATCH 2/2] Align giga mock balance validation with V2 --- app/app.go | 5 ++--- giga/deps/xevm/state/balance.go | 7 ------- giga/tests/giga_mock_balances_test.go | 3 +-- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/app/app.go b/app/app.go index be4f10cfcf..e6b4689541 100644 --- a/app/app.go +++ b/app/app.go @@ -3200,9 +3200,8 @@ func (app *App) validateGigaEVMTx( balanceCheck := new(big.Int).Mul(new(big.Int).SetUint64(ethTx.Gas()), ethTx.GasFeeCap()) balanceCheck.Add(balanceCheck, ethTx.Value()) - // Route validation balance handling through DBImpl so mock_balances can top - // up the sender via ensureSufficientBalance before the manual precheck. - stateDB.EnsureSufficientBalance(sender, balanceCheck) + // Route validation balance reads through DBImpl so mock_balances follows + // the same ensureMinimumBalance behavior as V2's StateTransition.BuyGas. senderBalance := stateDB.GetBalance(sender).ToBig() // Include the derived Sei address balance for unassociated addresses (matches V2 PreprocessDecorator). diff --git a/giga/deps/xevm/state/balance.go b/giga/deps/xevm/state/balance.go index 9d31ade609..2a7c1734ed 100644 --- a/giga/deps/xevm/state/balance.go +++ b/giga/deps/xevm/state/balance.go @@ -12,13 +12,6 @@ import ( var ZeroInt = uint256.NewInt(0) -func (s *DBImpl) EnsureSufficientBalance(evmAddr common.Address, amt *big.Int) { - if amt == nil || amt.Sign() <= 0 { - return - } - s.ensureSufficientBalance(evmAddr, amt) -} - func (s *DBImpl) SubBalance(evmAddr common.Address, amtUint256 *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int { amt := amtUint256.ToBig() if amt.Sign() == 0 { diff --git a/giga/tests/giga_mock_balances_test.go b/giga/tests/giga_mock_balances_test.go index e191255714..76dbdafe00 100644 --- a/giga/tests/giga_mock_balances_test.go +++ b/giga/tests/giga_mock_balances_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - gigaevmstate "github.com/sei-protocol/sei-chain/giga/deps/xevm/state" "github.com/sei-protocol/sei-chain/occ_tests/utils" "github.com/stretchr/testify/require" ) @@ -22,7 +21,7 @@ func TestGigaMockBalancesValidationUsesDBImpl(t *testing.T) { gigaCtx.TestApp.GigaEvmKeeper.SetAddressMapping(gigaCtx.Ctx, signer.AccountAddress, signer.EvmAddress) to := recipient.EvmAddress - value := new(big.Int).Mul(gigaevmstate.TopOffAmount, big.NewInt(2)) + value := big.NewInt(1_000_000_000_000_000_000) fee := big.NewInt(100000000000) tx := createCustomEVMTx(t, gigaCtx, signer, &to, value, 21000, fee, fee, 0)