-
Notifications
You must be signed in to change notification settings - Fork 874
feat: Giga RPC node (sequential execution) #2708
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
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
83738af
feat: Giga: support synchronous giga execution of blocks
arajasek 68e122c
Fix issue with lastresultshash mismatch (#2720)
stevenlanders 3af70a9
fix: 2 giga changes to match v2 behaviour (#2739)
arajasek f9ea4eb
bump to tagged go-ethereum
arajasek 1329116
fix: associate addresses matches v2 behaviour
arajasek 8c35752
fix lint
arajasek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| servertypes "github.com/cosmos/cosmos-sdk/server/types" | ||
| storetypes "github.com/cosmos/cosmos-sdk/store/types" | ||
| sdk "github.com/cosmos/cosmos-sdk/types" | ||
| sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
| genesistypes "github.com/cosmos/cosmos-sdk/types/genesis" | ||
| "github.com/cosmos/cosmos-sdk/types/module" | ||
| "github.com/cosmos/cosmos-sdk/types/occ" | ||
|
|
@@ -93,6 +94,7 @@ | |
| ethrpc "github.com/ethereum/go-ethereum/rpc" | ||
| "github.com/sei-protocol/sei-chain/giga/deps/tasks" | ||
|
|
||
| "github.com/gogo/protobuf/proto" | ||
| "github.com/gorilla/mux" | ||
| "github.com/rakyll/statik/fs" | ||
| "github.com/sei-protocol/sei-chain/app/antedecorators" | ||
|
|
@@ -105,6 +107,8 @@ | |
| gigaexecutor "github.com/sei-protocol/sei-chain/giga/executor" | ||
| gigaconfig "github.com/sei-protocol/sei-chain/giga/executor/config" | ||
| gigalib "github.com/sei-protocol/sei-chain/giga/executor/lib" | ||
| gigaprecompiles "github.com/sei-protocol/sei-chain/giga/executor/precompiles" | ||
| gigautils "github.com/sei-protocol/sei-chain/giga/executor/utils" | ||
| "github.com/sei-protocol/sei-chain/precompiles" | ||
| putils "github.com/sei-protocol/sei-chain/precompiles/utils" | ||
| ssconfig "github.com/sei-protocol/sei-chain/sei-db/config" | ||
|
|
@@ -1342,7 +1346,7 @@ | |
| } | ||
| } | ||
|
|
||
| func (app *App) ProcessBlockSynchronous(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) []*abci.ExecTxResult { | ||
| func (app *App) ProcessTxsSynchronousV2(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) []*abci.ExecTxResult { | ||
| defer metrics.BlockProcessLatency(time.Now(), metrics.SYNCHRONOUS) | ||
|
|
||
| txResults := []*abci.ExecTxResult{} | ||
|
|
@@ -1355,6 +1359,43 @@ | |
| return txResults | ||
| } | ||
|
|
||
| func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) []*abci.ExecTxResult { | ||
| defer metrics.BlockProcessLatency(time.Now(), metrics.SYNCHRONOUS) | ||
|
|
||
| txResults := make([]*abci.ExecTxResult, len(txs)) | ||
| for i, tx := range txs { | ||
| ctx = ctx.WithTxIndex(absoluteTxIndices[i]) | ||
| evmMsg := app.GetEVMMsg(typedTxs[i]) | ||
| // If not an EVM tx, fall back to v2 processing | ||
| if evmMsg == nil { | ||
| result := app.DeliverTxWithResult(ctx, tx, typedTxs[i]) | ||
| txResults[i] = result | ||
| continue | ||
| } | ||
|
|
||
| // Execute EVM transaction through giga executor | ||
| result, execErr := app.executeEVMTxWithGigaExecutor(ctx, evmMsg) | ||
| if execErr != nil { | ||
| // Check if this is a fail-fast error (Cosmos precompile interop detected) | ||
| if gigautils.ShouldExecutionAbort(execErr) { | ||
| res := app.DeliverTxWithResult(ctx, tx, typedTxs[i]) | ||
| txResults[i] = res | ||
| continue | ||
| } | ||
| txResults[i] = &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: fmt.Sprintf("[BUG] giga executor error: %v", execErr), | ||
| } | ||
| continue | ||
| } | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would need to call
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thank you! |
||
| txResults[i] = result | ||
| metrics.IncrTxProcessTypeCounter(metrics.SYNCHRONOUS) | ||
| } | ||
|
|
||
| return txResults | ||
| } | ||
|
|
||
| type ChannelResult struct { | ||
| txIndex int | ||
| result *abci.ExecTxResult | ||
|
|
@@ -1397,12 +1438,16 @@ | |
|
|
||
| // ExecuteTxsConcurrently calls the appropriate function for processing transacitons | ||
| func (app *App) ExecuteTxsConcurrently(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) ([]*abci.ExecTxResult, sdk.Context) { | ||
| // TODO after OCC release, remove this check and call ProcessTXsWithOCC directly | ||
| if ctx.IsOCCEnabled() { | ||
| return app.ProcessTXsWithOCC(ctx, txs, typedTxs, absoluteTxIndices) | ||
| // Giga only supports synchronous execution for now | ||
| if app.GigaExecutorEnabled { | ||
| results := app.ProcessTxsSynchronousGiga(ctx, txs, typedTxs, absoluteTxIndices) | ||
| return results, ctx | ||
| } else if !ctx.IsOCCEnabled() { | ||
| results := app.ProcessTxsSynchronousV2(ctx, txs, typedTxs, absoluteTxIndices) | ||
| return results, ctx | ||
| } | ||
| results := app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) | ||
| return results, ctx | ||
|
|
||
| return app.ProcessTXsWithOCC(ctx, txs, typedTxs, absoluteTxIndices) | ||
| } | ||
|
|
||
| func (app *App) GetDeliverTxEntry(ctx sdk.Context, txIndex int, absoluateIndex int, bz []byte, tx sdk.Tx) (res *sdk.DeliverTxEntry) { | ||
|
|
@@ -1461,6 +1506,7 @@ | |
| Codespace: r.Response.Codespace, | ||
| EvmTxInfo: r.Response.EvmTxInfo, | ||
| }) | ||
|
|
||
| } | ||
|
|
||
| return execResults, ctx | ||
|
|
@@ -1496,12 +1542,9 @@ | |
| } | ||
| }() | ||
|
|
||
| // Route to Giga Executor when enabled - bypasses Cosmos SDK transaction processing | ||
| if app.GigaExecutorEnabled { | ||
| if app.GigaOCCEnabled { | ||
| return app.ProcessBlockWithGigaExecutorOCC(ctx, txs, req, lastCommit, simulate) | ||
| } | ||
| return app.ProcessBlockWithGigaExecutor(ctx, txs, req, lastCommit, simulate) | ||
| // TODO: for now Giga OCC calls ProcessBlockWithGigaExecutorOCC, WIP | ||
| if app.GigaExecutorEnabled && app.GigaOCCEnabled { | ||
| return app.ProcessBlockWithGigaExecutorOCC(ctx, txs, req, lastCommit, simulate) | ||
| } | ||
|
|
||
| ctx = ctx.WithIsOCCEnabled(app.OccEnabled()) | ||
|
|
@@ -1564,6 +1607,7 @@ | |
| // ProcessBlockWithGigaExecutor executes block transactions using the Giga executor, | ||
| // bypassing the standard Cosmos SDK transaction processing flow. | ||
| // This is an experimental path for improved EVM throughput. | ||
| // NOTE: This is not currently used in the codebase, but might be in the future. | ||
| func (app *App) ProcessBlockWithGigaExecutor(ctx sdk.Context, txs [][]byte, req BlockProcessRequest, lastCommit abci.CommitInfo, simulate bool) (events []abci.Event, txResults []*abci.ExecTxResult, endBlockResp abci.ResponseEndBlock, err error) { | ||
| // Panic recovery like original ProcessBlock | ||
| defer func() { | ||
|
|
@@ -1614,23 +1658,26 @@ | |
| // Check if this is an EVM transaction | ||
| evmMsg := app.GetEVMMsg(decodedTx) | ||
| if evmMsg == nil { | ||
| // Non-EVM transaction - for now, fall back to standard processing | ||
| // TODO: Handle or reject non-EVM txs in giga mode | ||
| txResults[i] = &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: "non-EVM transactions not supported in giga executor mode", | ||
| } | ||
| res := app.DeliverTxWithResult(ctx, txBytes, decodedTx) | ||
| // Non-EVM transaction - fall back to standard processing | ||
| txResults[i] = res | ||
| continue | ||
| } | ||
|
|
||
| evmTxs[i] = evmMsg | ||
|
|
||
| // Execute EVM transaction through giga executor | ||
| result, execErr := app.executeEVMTxWithGigaExecutor(ctx, i, evmMsg) | ||
| result, execErr := app.executeEVMTxWithGigaExecutor(ctx, evmMsg) | ||
| if execErr != nil { | ||
| // Check if this is a fail-fast error (Cosmos precompile interop detected) | ||
| if gigautils.ShouldExecutionAbort(execErr) { | ||
| res := app.DeliverTxWithResult(ctx, txBytes, decodedTx) | ||
| txResults[i] = res | ||
| continue | ||
| } | ||
| txResults[i] = &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: fmt.Sprintf("giga executor error: %v", execErr), | ||
| Log: fmt.Sprintf("[BUG] giga executor error: %v", execErr), | ||
| } | ||
| continue | ||
| } | ||
|
|
@@ -1658,7 +1705,7 @@ | |
|
|
||
| // executeEVMTxWithGigaExecutor executes a single EVM transaction using the giga executor. | ||
| // The sender address is recovered directly from the transaction signature - no Cosmos SDK ante handlers needed. | ||
| func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, txIndex int, msg *evmtypes.MsgEVMTransaction) (*abci.ExecTxResult, error) { | ||
| func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgEVMTransaction) (*abci.ExecTxResult, error) { | ||
| // Get the Ethereum transaction from the message | ||
| ethTx, txData := msg.AsTransaction() | ||
| if ethTx == nil || txData == nil { | ||
|
|
@@ -1679,7 +1726,7 @@ | |
| // Associate the address if not already associated (same as EVMPreprocessDecorator) | ||
| if _, isAssociated := app.GigaEvmKeeper.GetEVMAddress(ctx, seiAddr); !isAssociated { | ||
| associateHelper := helpers.NewAssociationHelper(&app.GigaEvmKeeper, app.GigaBankKeeper, &app.AccountKeeper) | ||
| if err := associateHelper.AssociateAddresses(ctx, seiAddr, sender, pubkey, true); err != nil { | ||
| if err := associateHelper.AssociateAddresses(ctx, seiAddr, sender, pubkey, false); err != nil { | ||
| return &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: fmt.Sprintf("failed to associate addresses: %v", err), | ||
|
|
@@ -1689,7 +1736,6 @@ | |
|
|
||
| // Prepare context for EVM transaction (set infinite gas meter like original flow) | ||
| ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) | ||
| ctx = ctx.WithTxIndex(txIndex) | ||
|
|
||
| // Create state DB for this transaction | ||
| stateDB := gigaevmstate.NewDBImpl(ctx, &app.GigaEvmKeeper, false) | ||
|
|
@@ -1711,8 +1757,8 @@ | |
| sstore := app.GigaEvmKeeper.GetParams(ctx).SeiSstoreSetGasEip2200 | ||
| cfg := evmtypes.DefaultChainConfig().EthereumConfigWithSstore(app.GigaEvmKeeper.ChainID(ctx), &sstore) | ||
|
|
||
| // Create Giga executor VM (wraps evmone) | ||
| gigaExecutor := gigaexecutor.NewEvmoneExecutor(app.GigaEvmKeeper.EvmoneVM, *blockCtx, stateDB, cfg, vm.Config{}, app.GigaEvmKeeper.CustomPrecompiles(ctx)) | ||
| // Create Giga executor VM | ||
| gigaExecutor := gigaexecutor.NewGethExecutor(*blockCtx, stateDB, cfg, vm.Config{}, gigaprecompiles.AllCustomPrecompilesFailFast) | ||
|
|
||
| // Execute the transaction through giga VM | ||
| execResult, execErr := gigaExecutor.ExecuteTransaction(ethTx, sender, app.GigaEvmKeeper.GetBaseFee(ctx), &gp) | ||
|
|
@@ -1723,6 +1769,12 @@ | |
| }, nil | ||
| } | ||
|
|
||
| // Check if the execution hit a fail-fast precompile (Cosmos interop detected) | ||
| // Return the error to the caller so it can handle accordingly (e.g., fallback to standard execution) | ||
| if execResult.Err != nil && gigautils.ShouldExecutionAbort(execResult.Err) { | ||
| return nil, execResult.Err | ||
| } | ||
|
|
||
| // Finalize state changes | ||
| _, ferr := stateDB.Finalize() | ||
| if ferr != nil { | ||
|
|
@@ -1770,20 +1822,55 @@ | |
| // Determine result code based on VM error | ||
| code := uint32(0) | ||
| if execResult.Err != nil { | ||
| code = 1 | ||
| code = sdkerrors.ErrEVMVMError.ABCICode() | ||
| } | ||
|
|
||
| // GasWanted should be set to the transaction's gas limit to match standard executor behavior. | ||
| // This is critical for LastResultsHash computation which uses Code, Data, GasWanted, and GasUsed. | ||
| gasWanted := int64(ethTx.Gas()) //nolint:gosec // G115: safe, Gas() won't exceed int64 max | ||
| gasUsed := int64(execResult.UsedGas) //nolint:gosec // G115: safe, UsedGas won't exceed int64 max | ||
|
|
||
| // Build Data field to match standard executor format. | ||
| // Standard path wraps MsgEVMTransactionResponse in TxMsgData. | ||
| // This is critical for LastResultsHash to match. | ||
| evmResponse := &evmtypes.MsgEVMTransactionResponse{ | ||
| GasUsed: execResult.UsedGas, | ||
| VmError: vmError, | ||
| ReturnData: execResult.ReturnData, | ||
| Hash: ethTx.Hash().Hex(), | ||
| Logs: evmtypes.NewLogsFromEth(stateDB.GetAllLogs()), | ||
| } | ||
| evmResponseBytes, marshalErr := evmResponse.Marshal() | ||
| if marshalErr != nil { | ||
| return &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: fmt.Sprintf("failed to marshal evm response: %v", marshalErr), | ||
| }, nil | ||
| } | ||
|
|
||
| // Serialize receipt to include in response Data field. | ||
| // In OCC mode, transient store writes are lost because the CacheMultiStore | ||
| // isn't committed, so we pass the receipt through the response for later processing. | ||
| receiptBytes, _ := receipt.Marshal() | ||
| // Wrap in TxMsgData like the standard path does | ||
| txMsgData := &sdk.TxMsgData{ | ||
| Data: []*sdk.MsgData{ | ||
| { | ||
| MsgType: sdk.MsgTypeURL(msg), | ||
| Data: evmResponseBytes, | ||
| }, | ||
| }, | ||
| } | ||
| txMsgDataBytes, txMarshalErr := proto.Marshal(txMsgData) | ||
| if txMarshalErr != nil { | ||
| return &abci.ExecTxResult{ | ||
| Code: 1, | ||
| Log: fmt.Sprintf("failed to marshal tx msg data: %v", txMarshalErr), | ||
| }, nil | ||
| } | ||
|
|
||
| //nolint:gosec // G115: safe, UsedGas won't exceed int64 max | ||
| return &abci.ExecTxResult{ | ||
| Code: code, | ||
| Data: receiptBytes, | ||
| GasUsed: int64(execResult.UsedGas), | ||
| Log: vmError, | ||
| Code: code, | ||
| Data: txMsgDataBytes, | ||
| GasWanted: gasWanted, | ||
| GasUsed: gasUsed, | ||
| Log: vmError, | ||
| EvmTxInfo: &abci.EvmTxInfo{ | ||
| TxHash: ethTx.Hash().Hex(), | ||
| VmError: vmError, | ||
|
|
@@ -1879,19 +1966,22 @@ | |
| evmTotalGasUsed += resp.GasUsed | ||
|
|
||
| // Restore transient store data using main context | ||
| if resp.Code == 0 && len(resp.Data) > 0 && evmTxs[idx] != nil { | ||
| receipt := &evmtypes.Receipt{} | ||
| if err := receipt.Unmarshal(resp.Data); err == nil { | ||
| ethTx, _ := evmTxs[idx].AsTransaction() | ||
| if ethTx != nil { | ||
| txHash := ethTx.Hash() | ||
| // Write receipt to transient store using main context | ||
| _ = app.EvmKeeper.SetTransientReceipt(ctx.WithTxIndex(idx), txHash, receipt) | ||
| // Write deferred info using main context | ||
| bloom := ethtypes.Bloom{} | ||
| bloom.SetBytes(receipt.LogsBloom) | ||
| app.EvmKeeper.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(idx), bloom, txHash, sdk.ZeroInt()) | ||
| // In OCC mode, the Data field contains TxMsgData (standard format) for correct LastResultsHash. | ||
| // We need to extract the receipt info from the response or reconstruct it. | ||
| if resp.Code == 0 && evmTxs[idx] != nil { | ||
| ethTx, _ := evmTxs[idx].AsTransaction() | ||
| if ethTx != nil { | ||
| txHash := ethTx.Hash() | ||
| // In OCC mode, the receipt was written during execution but may have been lost. | ||
| // We can reconstruct minimal receipt info from the response for deferred processing. | ||
| // The full receipt details would need to be fetched from transient store if it exists. | ||
| bloom := ethtypes.Bloom{} | ||
| // Try to get receipt from transient store (may exist if execution succeeded) | ||
| existingReceipt, receiptErr := app.EvmKeeper.GetTransientReceipt(ctx.WithTxIndex(idx), txHash, uint64(idx)) //nolint:gosec // G115: idx is a valid tx index, always non-negative | ||
| if receiptErr == nil && existingReceipt != nil { | ||
| bloom.SetBytes(existingReceipt.LogsBloom) | ||
| } | ||
| app.EvmKeeper.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(idx), bloom, txHash, sdk.ZeroInt()) | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -1940,8 +2030,14 @@ | |
| return abci.ResponseDeliverTx{Code: 1, Log: "not an EVM transaction"} | ||
| } | ||
|
|
||
| result, err := app.executeEVMTxWithGigaExecutor(ctx, ctx.TxIndex(), evmMsg) | ||
| result, err := app.executeEVMTxWithGigaExecutor(ctx, evmMsg) | ||
| if err != nil { | ||
| // Check if this is a fail-fast error (Cosmos precompile interop detected) | ||
| if gigautils.ShouldExecutionAbort(err) { | ||
| // Transaction requires Cosmos interop - not supported in giga mode | ||
| // TODO: implement fallback to standard execution path | ||
| return abci.ResponseDeliverTx{Code: 1, Log: fmt.Sprintf("giga executor: cosmos interop not supported: %v", err)} | ||
| } | ||
| return abci.ResponseDeliverTx{Code: 1, Log: fmt.Sprintf("giga executor error: %v", err)} | ||
| } | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,17 @@ | ||
| package utils | ||
|
|
||
| import ( | ||
| "errors" | ||
|
|
||
| "github.com/sei-protocol/sei-chain/giga/executor/precompiles" | ||
| "github.com/ethereum/go-ethereum/core/vm" | ||
| ) | ||
|
|
||
| // ShouldExecutionAbort checks if the given error is an AbortError that should | ||
| // cause Giga execution to abort and fall back to standard execution. | ||
| func ShouldExecutionAbort(err error) bool { | ||
| return errors.Is(err, precompiles.ErrInvalidPrecompileCall) | ||
| if err == nil { | ||
| return false | ||
| } | ||
| if abortErr, ok := err.(vm.AbortError); ok { | ||
| return abortErr.IsAbortError() | ||
| } | ||
| return false | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check warning
Code scanning / CodeQL
Calling the system time Warning