99 "fmt"
1010 "io"
1111 "math"
12+ "math/big"
1213 "net/http"
1314 "os"
1415 "path/filepath"
@@ -92,6 +93,7 @@ import (
9293 ethtypes "github.com/ethereum/go-ethereum/core/types"
9394 "github.com/ethereum/go-ethereum/core/vm"
9495 "github.com/ethereum/go-ethereum/ethclient"
96+ ethparams "github.com/ethereum/go-ethereum/params"
9597 ethrpc "github.com/ethereum/go-ethereum/rpc"
9698 "github.com/sei-protocol/sei-chain/giga/deps/tasks"
9799
@@ -318,6 +320,33 @@ func GetWasmEnabledProposals() []wasm.ProposalType {
318320// App extends an ABCI application, but with most of its parameters exported.
319321// They are exported for convenience in creating helper functions, as object
320322// capabilities aren't needed for testing.
323+ // gigaBlockCache holds block-constant values that are identical for all txs in a block.
324+ // Populated once before block execution, read-only during parallel execution, cleared after.
325+ type gigaBlockCache struct {
326+ chainID * big.Int
327+ blockCtx vm.BlockContext
328+ chainConfig * ethparams.ChainConfig
329+ baseFee * big.Int
330+ }
331+
332+ func newGigaBlockCache (ctx sdk.Context , keeper * gigaevmkeeper.Keeper ) (* gigaBlockCache , error ) {
333+ chainID := keeper .ChainID (ctx )
334+ gp := keeper .GetGasPool ()
335+ blockCtx , err := keeper .GetVMBlockContext (ctx , gp )
336+ if err != nil {
337+ return nil , err
338+ }
339+ sstore := keeper .GetParams (ctx ).SeiSstoreSetGasEip2200
340+ chainConfig := evmtypes .DefaultChainConfig ().EthereumConfigWithSstore (chainID , & sstore )
341+ baseFee := keeper .GetBaseFee (ctx )
342+ return & gigaBlockCache {
343+ chainID : chainID ,
344+ blockCtx : * blockCtx ,
345+ chainConfig : chainConfig ,
346+ baseFee : baseFee ,
347+ }, nil
348+ }
349+
321350type App struct {
322351 * baseapp.BaseApp
323352
@@ -1373,6 +1402,14 @@ func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTx
13731402 ms := ctx .MultiStore ().CacheMultiStore ()
13741403 defer ms .Write ()
13751404 ctx = ctx .WithMultiStore (ms )
1405+
1406+ // Cache block-level constants (identical for all txs in this block).
1407+ cache , cacheErr := newGigaBlockCache (ctx , & app .GigaEvmKeeper )
1408+ if cacheErr != nil {
1409+ ctx .Logger ().Error ("failed to build giga block cache" , "error" , cacheErr , "height" , ctx .BlockHeight ())
1410+ return nil
1411+ }
1412+
13761413 txResults := make ([]* abci.ExecTxResult , len (txs ))
13771414 for i , tx := range txs {
13781415 ctx = ctx .WithTxIndex (absoluteTxIndices [i ])
@@ -1386,7 +1423,7 @@ func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTx
13861423 }
13871424
13881425 // Execute EVM transaction through giga executor
1389- result , execErr := app .executeEVMTxWithGigaExecutor (ctx , evmMsg )
1426+ result , execErr := app .executeEVMTxWithGigaExecutor (ctx , evmMsg , cache )
13901427 if execErr != nil {
13911428 // Check if this is a fail-fast error (Cosmos precompile interop detected)
13921429 if gigautils .ShouldExecutionAbort (execErr ) {
@@ -1544,15 +1581,24 @@ func (app *App) ProcessTXsWithOCCGiga(ctx sdk.Context, txs [][]byte, typedTxs []
15441581 }
15451582 }
15461583
1547- // Create OCC scheduler with giga executor deliverTx.
1584+ // Run EVM txs against a cache so we can discard all changes on fallback.
1585+ evmCtx , evmCache := app .CacheContext (ctx )
1586+
1587+ // Cache block-level constants (identical for all txs in this block).
1588+ // Must use evmCtx (not ctx) because giga KV stores are registered in CacheContext.
1589+ cache , cacheErr := newGigaBlockCache (evmCtx , & app .GigaEvmKeeper )
1590+ if cacheErr != nil {
1591+ ctx .Logger ().Error ("failed to build giga block cache" , "error" , cacheErr , "height" , ctx .BlockHeight ())
1592+ return nil , ctx
1593+ }
1594+
1595+ // Create OCC scheduler with giga executor deliverTx capturing the cache.
15481596 evmScheduler := tasks .NewScheduler (
15491597 app .ConcurrencyWorkers (),
15501598 app .TracingInfo ,
1551- app .gigaDeliverTx ,
1599+ app .makeGigaDeliverTx ( cache ) ,
15521600 )
15531601
1554- // Run EVM txs against a cache so we can discard all changes on fallback.
1555- evmCtx , evmCache := app .CacheContext (ctx )
15561602 evmBatchResult , evmSchedErr := evmScheduler .ProcessAll (evmCtx , evmEntries )
15571603 if evmSchedErr != nil {
15581604 // TODO: DeliverTxBatch panics in this case
@@ -1713,14 +1759,14 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ
17131759
17141760// executeEVMTxWithGigaExecutor executes a single EVM transaction using the giga executor.
17151761// The sender address is recovered directly from the transaction signature - no Cosmos SDK ante handlers needed.
1716- func (app * App ) executeEVMTxWithGigaExecutor (ctx sdk.Context , msg * evmtypes.MsgEVMTransaction ) (* abci.ExecTxResult , error ) {
1762+ func (app * App ) executeEVMTxWithGigaExecutor (ctx sdk.Context , msg * evmtypes.MsgEVMTransaction , cache * gigaBlockCache ) (* abci.ExecTxResult , error ) {
17171763 // Get the Ethereum transaction from the message
17181764 ethTx , txData := msg .AsTransaction ()
17191765 if ethTx == nil || txData == nil {
17201766 return nil , fmt .Errorf ("failed to convert to eth transaction" )
17211767 }
17221768
1723- chainID := app . GigaEvmKeeper . ChainID ( ctx )
1769+ chainID := cache . chainID
17241770
17251771 // Recover sender using the same logic as preprocess.go (version-based signer selection)
17261772 sender , seiAddr , pubkey , recoverErr := evmante .RecoverSenderFromEthTx (ctx , ethTx , chainID )
@@ -1749,27 +1795,18 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE
17491795 stateDB := gigaevmstate .NewDBImpl (ctx , & app .GigaEvmKeeper , false )
17501796 defer stateDB .Cleanup ()
17511797
1752- // Get gas pool
1798+ // Get gas pool (mutated per tx, cannot be cached)
17531799 gp := app .GigaEvmKeeper .GetGasPool ()
17541800
1755- // Get block context
1756- blockCtx , blockCtxErr := app .GigaEvmKeeper .GetVMBlockContext (ctx , gp )
1757- if blockCtxErr != nil {
1758- return & abci.ExecTxResult {
1759- Code : 1 ,
1760- Log : fmt .Sprintf ("failed to get block context: %v" , blockCtxErr ),
1761- }, nil
1762- }
1763-
1764- // Get chain config
1765- sstore := app .GigaEvmKeeper .GetParams (ctx ).SeiSstoreSetGasEip2200
1766- cfg := evmtypes .DefaultChainConfig ().EthereumConfigWithSstore (app .GigaEvmKeeper .ChainID (ctx ), & sstore )
1801+ // Use cached block-level constants
1802+ blockCtx := cache .blockCtx
1803+ cfg := cache .chainConfig
17671804
17681805 // Create Giga executor VM
1769- gigaExecutor := gigaexecutor .NewGethExecutor (* blockCtx , stateDB , cfg , vm.Config {}, gigaprecompiles .AllCustomPrecompilesFailFast )
1806+ gigaExecutor := gigaexecutor .NewGethExecutor (blockCtx , stateDB , cfg , vm.Config {}, gigaprecompiles .AllCustomPrecompilesFailFast )
17701807
17711808 // Execute the transaction through giga VM
1772- execResult , execErr := gigaExecutor .ExecuteTransaction (ethTx , sender , app . GigaEvmKeeper . GetBaseFee ( ctx ) , & gp )
1809+ execResult , execErr := gigaExecutor .ExecuteTransaction (ethTx , sender , cache . baseFee , & gp )
17731810 if execErr != nil {
17741811 return & abci.ExecTxResult {
17751812 Code : 1 ,
@@ -1888,49 +1925,52 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE
18881925}
18891926
18901927// gigaDeliverTx is the OCC-compatible deliverTx function for the giga executor.
1891- // The ctx.MultiStore() is already wrapped with VersionIndexedStore by the scheduler.
1892- func (app * App ) gigaDeliverTx (ctx sdk.Context , req abci.RequestDeliverTxV2 , tx sdk.Tx , checksum [32 ]byte ) abci.ResponseDeliverTx {
1893- defer func () {
1894- if r := recover (); r != nil {
1895- // OCC abort panics are expected - the scheduler uses them to detect conflicts
1896- // and reschedule transactions. Don't log these as errors.
1897- if _ , isOCCAbort := r .(occ.Abort ); ! isOCCAbort {
1898- ctx .Logger ().Error ("benchmark panic in gigaDeliverTx" , "panic" , r , "stack" , string (debug .Stack ()))
1928+ // makeGigaDeliverTx returns an OCC-compatible deliverTx callback that captures the given
1929+ // block cache, avoiding mutable state on App for cache lifecycle management.
1930+ func (app * App ) makeGigaDeliverTx (cache * gigaBlockCache ) func (sdk.Context , abci.RequestDeliverTxV2 , sdk.Tx , [32 ]byte ) abci.ResponseDeliverTx {
1931+ return func (ctx sdk.Context , req abci.RequestDeliverTxV2 , tx sdk.Tx , checksum [32 ]byte ) abci.ResponseDeliverTx {
1932+ defer func () {
1933+ if r := recover (); r != nil {
1934+ // OCC abort panics are expected - the scheduler uses them to detect conflicts
1935+ // and reschedule transactions. Don't log these as errors.
1936+ if _ , isOCCAbort := r .(occ.Abort ); ! isOCCAbort {
1937+ ctx .Logger ().Error ("benchmark panic in gigaDeliverTx" , "panic" , r , "stack" , string (debug .Stack ()))
1938+ }
18991939 }
1900- }
1901- }()
1940+ }()
19021941
1903- evmMsg := app .GetEVMMsg (tx )
1904- if evmMsg == nil {
1905- return abci.ResponseDeliverTx {Code : 1 , Log : "not an EVM transaction" }
1906- }
1942+ evmMsg := app .GetEVMMsg (tx )
1943+ if evmMsg == nil {
1944+ return abci.ResponseDeliverTx {Code : 1 , Log : "not an EVM transaction" }
1945+ }
19071946
1908- result , err := app .executeEVMTxWithGigaExecutor (ctx , evmMsg )
1909- if err != nil {
1910- // Check if this is a fail-fast error (Cosmos precompile interop detected)
1911- if gigautils .ShouldExecutionAbort (err ) {
1912- // Return a sentinel response so the caller can fall back to v2.
1913- return abci.ResponseDeliverTx {
1914- Code : gigautils .GigaAbortCode ,
1915- Codespace : gigautils .GigaAbortCodespace ,
1916- Info : gigautils .GigaAbortInfo ,
1917- Log : "giga executor abort: fall back to v2" ,
1947+ result , err := app .executeEVMTxWithGigaExecutor (ctx , evmMsg , cache )
1948+ if err != nil {
1949+ // Check if this is a fail-fast error (Cosmos precompile interop detected)
1950+ if gigautils .ShouldExecutionAbort (err ) {
1951+ // Return a sentinel response so the caller can fall back to v2.
1952+ return abci.ResponseDeliverTx {
1953+ Code : gigautils .GigaAbortCode ,
1954+ Codespace : gigautils .GigaAbortCodespace ,
1955+ Info : gigautils .GigaAbortInfo ,
1956+ Log : "giga executor abort: fall back to v2" ,
1957+ }
19181958 }
1919- }
19201959
1921- return abci.ResponseDeliverTx {Code : 1 , Log : fmt .Sprintf ("giga executor error: %v" , err )}
1922- }
1960+ return abci.ResponseDeliverTx {Code : 1 , Log : fmt .Sprintf ("giga executor error: %v" , err )}
1961+ }
19231962
1924- return abci.ResponseDeliverTx {
1925- Code : result .Code ,
1926- Data : result .Data ,
1927- Log : result .Log ,
1928- Info : result .Info ,
1929- GasWanted : result .GasWanted ,
1930- GasUsed : result .GasUsed ,
1931- Events : result .Events ,
1932- Codespace : result .Codespace ,
1933- EvmTxInfo : result .EvmTxInfo ,
1963+ return abci.ResponseDeliverTx {
1964+ Code : result .Code ,
1965+ Data : result .Data ,
1966+ Log : result .Log ,
1967+ Info : result .Info ,
1968+ GasWanted : result .GasWanted ,
1969+ GasUsed : result .GasUsed ,
1970+ Events : result .Events ,
1971+ Codespace : result .Codespace ,
1972+ EvmTxInfo : result .EvmTxInfo ,
1973+ }
19341974 }
19351975}
19361976
0 commit comments