diff --git a/.cursor/rules/xlayer-db.mdc b/.cursor/rules/xlayer-db.mdc index 2081b74957..c8de0aff26 100644 --- a/.cursor/rules/xlayer-db.mdc +++ b/.cursor/rules/xlayer-db.mdc @@ -43,10 +43,6 @@ globs: - "cmd/geth/dbcmd.go" - "core/rawdb/*_test.go" - "core/rawdb/ancienttest/**/*.go" -- "core/rawdb/accessors_inner_tx_xlayer.go" -- "core/types/innertx_xlayer.go" -- "core/state_processor_xlayer.go" -- "core/vm/evm_xlayer.go" alwaysApply: false --- diff --git a/cmd/utils/flags_xlayer.go b/cmd/utils/flags_xlayer.go index 176220ed70..19cb97338d 100644 --- a/cmd/utils/flags_xlayer.go +++ b/cmd/utils/flags_xlayer.go @@ -15,13 +15,6 @@ import ( ) var ( - // InnerTx - InnerTxFlag = &cli.BoolFlag{ - Name: "innertx", - Usage: "Enable inner transaction capture and storage (disabled by default)", - Value: false, - Category: flags.XLayerCategory, - } // Migration flags for XLayer routing MigrationBlockFlag = &cli.Uint64Flag{ Name: "migration-block", @@ -55,7 +48,6 @@ var ( // XLayerFlags are the default flags for X Layer features XLayerFlags = []cli.Flag{ - InnerTxFlag, MigrationBlockFlag, PPRPCUrlFlag, PPRPCTimeoutFlag, @@ -66,17 +58,10 @@ var ( // SetXLayerConfig is a public wrapper function to internally call all XLayer configuration functions func SetXLayerConfig(ctx *cli.Context, cfg *ethconfig.Config) { - setInnerTxXLayer(ctx, cfg) setMigrationXLayer(ctx, cfg) setMonitorXLayer(ctx, cfg) } -func setInnerTxXLayer(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.IsSet(InnerTxFlag.Name) { - cfg.XLayer.EnableInnerTx = ctx.Bool(InnerTxFlag.Name) - } -} - func setMigrationXLayer(ctx *cli.Context, cfg *ethconfig.Config) { // Migration configuration if ctx.IsSet(MigrationBlockFlag.Name) { diff --git a/core/blockchain.go b/core/blockchain.go index 4032796a8c..de271d4a4e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1085,17 +1085,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // removed by the hc.SetHead function. rawdb.DeleteBody(db, hash, num) rawdb.DeleteReceipts(db, hash, num) - - // For X Layer - // Delete inner transactions for this block during SetHead rollback - if block := bc.GetBlock(hash, num); block != nil { - txCount := len(block.Transactions()) - if err := rawdb.DeleteBlockInnerTxs(db, num, txCount); err != nil { - log.Error("Failed to delete inner transactions during SetHead rollback", - "block", num, "hash", hash, "err", err) - // Continue with rollback even if inner tx deletion fails - } - } } // Todo(rjl493456442) txlookup, log index, etc @@ -1629,31 +1618,19 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { // writeBlockWithState writes block, metadata and corresponding state data to the // database. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB, sortedInnerTxs [][]*types.InnerTx) error { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB) error { if !bc.HasHeader(block.ParentHash(), block.NumberU64()-1) { return consensus.ErrUnknownAncestor } // Irrelevant of the canonical status, write the block itself to the database. // - // Note all the components of block(hash->number map, header, body, receipts, innerTxs) + // Note all the components of block(hash->number map, header, body, receipts) // should be written atomically. BlockBatch is used for containing all components. blockBatch := bc.db.NewBatch() rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) rawdb.WritePreimages(blockBatch, statedb.Preimages()) - // For X Layer - // Write inner transactions for each transaction in the block - for i, txInnerTxs := range sortedInnerTxs { - if len(txInnerTxs) > 0 { - if err := rawdb.WriteInnerTxs(blockBatch, block.NumberU64(), uint32(i), txInnerTxs); err != nil { - log.Error("Failed to write inner transactions to batch", - "block", block.NumberU64(), "tx", i, "count", len(txInnerTxs), "err", err) - // Continue processing even if inner tx storage fails - } - } - } - if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } @@ -1728,8 +1705,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead. // This function expects the chain mutex to be held. -func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool, innerTxs [][]*types.InnerTx) (status WriteStatus, err error) { - if err := bc.writeBlockWithState(block, receipts, state, innerTxs); err != nil { +func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { + if err := bc.writeBlockWithState(block, receipts, state); err != nil { return NonStatTy, err } currentBlock := bc.CurrentBlock() @@ -2209,9 +2186,9 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s ) if !setHead { // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, res.Receipts, statedb, res.InnerTxs) + err = bc.writeBlockWithState(block, res.Receipts, statedb) } else { - status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false, res.InnerTxs) + status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false) } if err != nil { return nil, err @@ -2601,11 +2578,6 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error rawdb.DeleteTxLookupEntry(batch, tx) } - // For X Layer - delete inner transactions for all deleted blocks - for _, block := range deletedBlocks { - rawdb.DeleteBlockInnerTxsBatch(batch, block.Number().Uint64(), len(block.Transactions())) - } - // Delete all hash markers that are not part of the new canonical chain. // Because the reorg function does not handle new chain head, all hash // markers greater than or equal to new chain head should be deleted. diff --git a/core/rawdb/accessors_inner_tx_xlayer.go b/core/rawdb/accessors_inner_tx_xlayer.go deleted file mode 100644 index 44d2ddb9da..0000000000 --- a/core/rawdb/accessors_inner_tx_xlayer.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2024 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rawdb - -import ( - "encoding/binary" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" -) - -// Key format: "InnerTx" + blockNum (uint64 big endian) + txIndex (uint32 big endian) -> RLP([]*InnerTx) - -const InnerTxPrefix = "InnerTx" - -// innerTxKey generates the database key for inner transactions -// Key format: "InnerTx" + blockNum (uint64 big endian) + txIndex (uint32 big endian) -func innerTxKey(blockNum uint64, txIndex uint32) []byte { - key := make([]byte, len(InnerTxPrefix)+8+4) - copy(key, InnerTxPrefix) - binary.BigEndian.PutUint64(key[len(InnerTxPrefix):], blockNum) - binary.BigEndian.PutUint32(key[len(InnerTxPrefix)+8:], txIndex) - return key -} - -// WriteInnerTxs stores inner transactions for a specific transaction in a block -func WriteInnerTxs(db ethdb.KeyValueWriter, blockNum uint64, txIndex uint32, innerTxs []*types.InnerTx) error { - if len(innerTxs) == 0 { - return nil - } - - key := innerTxKey(blockNum, txIndex) - - data, err := rlp.EncodeToBytes(innerTxs) - if err != nil { - return err - } - - return db.Put(key, data) -} - -// ReadInnerTxs retrieves inner transactions for a specific transaction in a block -func ReadInnerTxs(db ethdb.KeyValueReader, blockNum uint64, txIndex uint32) ([]*types.InnerTx, error) { - key := innerTxKey(blockNum, txIndex) - - // First check if the key exists to distinguish between "not found" and "database error" - exists, err := db.Has(key) - if err != nil { - return nil, err // Database error - } - if !exists { - return []*types.InnerTx{}, nil // Key doesn't exist, return empty slice - } - - data, err := db.Get(key) - if err != nil { - return nil, err - } - - var innerTxs []*types.InnerTx - if err := rlp.DecodeBytes(data, &innerTxs); err != nil { - return nil, err - } - return innerTxs, nil -} - -// ReadInnerTxsByTxHash retrieves inner transactions by transaction hash -// This requires looking up the block number and transaction index first -func ReadInnerTxsByTxHash(db ethdb.Reader, txHash common.Hash) ([]*types.InnerTx, error) { - blockNumber := ReadTxLookupEntry(db, txHash) - if blockNumber == nil { - return nil, nil - } - - // Get the block to find the transaction index - block := ReadBlock(db, ReadCanonicalHash(db, *blockNumber), *blockNumber) - if block == nil { - return nil, nil - } - - // Find the transaction index within the block - txIndex := -1 - for i, tx := range block.Transactions() { - if tx.Hash() == txHash { - txIndex = i - break - } - } - - if txIndex == -1 { - return nil, nil - } - - return ReadInnerTxs(db, *blockNumber, uint32(txIndex)) -} - -// DeleteBlockInnerTxs removes inner transactions for all transactions in a block -func DeleteBlockInnerTxs(db ethdb.KeyValueWriter, blockNum uint64, txCount int) error { - for txIndex := 0; txIndex < txCount; txIndex++ { - key := innerTxKey(blockNum, uint32(txIndex)) - if err := db.Delete(key); err != nil { - log.Error("Failed to delete inner transactions", "block", blockNum, "tx", txIndex, "err", err) - } - } - return nil -} - -// DeleteBlockInnerTxsBatch adds inner transaction deletion operations for an entire block to a batch -func DeleteBlockInnerTxsBatch(batch ethdb.Batch, blockNum uint64, txCount int) { - for txIndex := 0; txIndex < txCount; txIndex++ { - key := innerTxKey(blockNum, uint32(txIndex)) - if err := batch.Delete(key); err != nil { - log.Error("Failed to delete inner transactions", "block", blockNum, "tx", txIndex, "err", err) - } - } -} diff --git a/core/state_processor.go b/core/state_processor.go index 0e483b7920..b1b955b4bf 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -66,10 +66,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockHash = block.Hash() blockNumber = block.Number() allLogs []*types.Log - gp = new(GasPool).AddGas(block.GasLimit()) - - // For X Layer - allInnerTxs [][]*types.InnerTx + gp = new(GasPool).AddGas(block.GasLimit()) ) // Mutate the block and state according to any hard-fork specs @@ -104,16 +101,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } statedb.SetTxContext(tx.Hash(), i) - receipt, innerTxs, err := ApplyTransactionWithEVM_XLayer(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm) + receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) - - // For X Layer - allInnerTxs = append(allInnerTxs, innerTxs) } isIsthmus := config.IsIsthmus(block.Time()) @@ -147,10 +141,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg Receipts: receipts, Requests: requests, Logs: allLogs, - GasUsed: *usedGas, - - // For X Layer - InnerTxs: allInnerTxs, + GasUsed: *usedGas, }, nil } diff --git a/core/state_processor_xlayer.go b/core/state_processor_xlayer.go deleted file mode 100644 index 61f582d102..0000000000 --- a/core/state_processor_xlayer.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package core - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" -) - -func ApplyTransactionWithEVM_XLayer(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, innerTXs []*types.InnerTx, err error) { - if hooks := evm.Config.Tracer; hooks != nil { - if hooks.OnTxStart != nil { - hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) - } - if hooks.OnTxEnd != nil { - defer func() { hooks.OnTxEnd(receipt, err) }() - } - } - - nonce := tx.Nonce() - if msg.IsDepositTx && evm.ChainConfig().IsOptimismRegolith(evm.Context.Time) { - nonce = statedb.GetNonce(msg.From) - } - - // Apply the transaction to the current state (included in the env). - result, err := ApplyMessage(evm, msg, gp) - if err != nil { - return nil, nil, err - } - // Update the state with pending changes. - var root []byte - if evm.ChainConfig().IsByzantium(blockNumber) { - evm.StateDB.Finalise(true) - } else { - root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes() - } - *usedGas += result.UsedGas - - // Merge the tx-local access event into the "block-local" one, in order to collect - // all values, so that the witness can be built. - if statedb.Database().TrieDB().IsVerkle() { - statedb.AccessEvents().Merge(evm.AccessEvents) - } - - // For X Layer - var innerTxs []*types.InnerTx - if evm.Config.EnableInnerTxs { - innerTxs = afterApplyTransaction(evm, result.Failed()) - } - - return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root, evm.ChainConfig(), nonce), innerTxs, nil -} - -func afterApplyTransaction(env *vm.EVM, failed bool) []*types.InnerTx { - innerTxs := env.PopInnerTxs() - if failed { - for _, innerTx := range innerTxs { - innerTx.IsError = true - } - } - return innerTxs -} diff --git a/core/state_transition.go b/core/state_transition.go index c9a0b403e9..bc177ee9db 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -23,7 +23,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -583,26 +582,12 @@ func (st *stateTransition) innerExecute() (*ExecutionResult, error) { st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) var ( - ret []byte - vmerr error // vm errors do not effect consensus and are therefore not assigned to err - contractAddr common.Address + ret []byte + vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) - // For X Layer - innerTx := &types.InnerTx{ - Dept: *big.NewInt(0), - From: msg.From.String(), - IsError: false, - Gas: st.gasRemaining + gas, - ValueWei: st.msg.Value.String(), - CallValueWei: hexutil.EncodeBig(st.msg.Value), - } - st.evm.AddInnerTx(innerTx) if contractCreation { - ret, contractAddr, st.gasRemaining, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining, value) - - // For X Layer - innerTx.To = contractAddr.String() + ret, _, st.gasRemaining, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining, value) } else { // Increment the nonce for the next transaction. st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall) @@ -626,18 +611,6 @@ func (st *stateTransition) innerExecute() (*ExecutionResult, error) { // Execute the transaction's call. ret, st.gasRemaining, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value) - - // For X Layer - innerTx.To = msg.To.String() - } - - // For X Layer - if ret != nil { - innerTx.Output = hexutil.Encode(ret[:]) - } - if vmerr != nil { - innerTx.Error = vmerr.Error() - innerTx.IsError = true } // OP-Stack: pre-Regolith: if deposit, skip refunds, skip tipping coinbase @@ -736,9 +709,6 @@ func (st *stateTransition) innerExecute() (*ExecutionResult, error) { } } - // For X Layer - innerTx.GasUsed = st.gasUsed() - return &ExecutionResult{ UsedGas: st.gasUsed(), MaxUsedGas: peakGasUsed, diff --git a/core/types.go b/core/types.go index c45c21837c..204bbd0590 100644 --- a/core/types.go +++ b/core/types.go @@ -56,8 +56,5 @@ type ProcessResult struct { Receipts types.Receipts Requests [][]byte Logs []*types.Log - GasUsed uint64 - - // For X Layer - InnerTxs [][]*types.InnerTx // Inner transactions for each transaction in the block + GasUsed uint64 } diff --git a/core/types/innertx_xlayer.go b/core/types/innertx_xlayer.go deleted file mode 100644 index c5dcc3ad4d..0000000000 --- a/core/types/innertx_xlayer.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import "math/big" - -// InnerTx stores the basic field of an inner tx. -// NOTE: DON'T change this struct for: -// 1. It will be written to database, and must be keep the same type When reading history data from db -// 2. It will be returned by rpc method -type InnerTx struct { - Dept big.Int `json:"dept"` - InternalIndex big.Int `json:"internal_index"` - CallType string `json:"call_type"` - Name string `json:"name"` - TraceAddress string `json:"trace_address"` - CodeAddress string `json:"code_address"` - From string `json:"from"` - To string `json:"to"` - Input string `json:"input"` - Output string `json:"output"` - IsError bool `json:"is_error"` - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gas_used"` - Value string `json:"value"` - ValueWei string `json:"value_wei"` - CallValueWei string `json:"call_value_wei"` - Error string `json:"error"` -} diff --git a/core/vm/evm.go b/core/vm/evm.go index b885b8f1af..c0db42f2ca 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -130,9 +130,6 @@ type EVM struct { // precompiles holds the precompiled contracts for the current epoch precompiles map[common.Address]PrecompiledContract - // For X Layer - innerTxMeta *InnerTxMeta - // jumpDests stores results of JUMPDEST analysis. jumpDests JumpDestCache @@ -155,13 +152,6 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), - // For X Layer - innerTxMeta: &InnerTxMeta{ - lastDepth: 0, - indexMap: map[int]int{0: 0}, - InnerTxs: make([]*types.InnerTx, 0), - }, - jumpDests: newMapJumpDests(), hasher: crypto.NewKeccakState(), } @@ -236,14 +226,6 @@ func (evm *EVM) SetTxContext(txCtx TxContext) { txCtx.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache()) } evm.TxContext = txCtx - - // For X Layer - evm.innerTxMeta = &InnerTxMeta{ - index: 0, - lastDepth: 0, - indexMap: map[int]int{0: 0}, - InnerTxs: make([]*types.InnerTx, 0), - } } // Cancel cancels any running EVM operation. This may be called concurrently and diff --git a/core/vm/evm_xlayer.go b/core/vm/evm_xlayer.go deleted file mode 100644 index 20dd183494..0000000000 --- a/core/vm/evm_xlayer.go +++ /dev/null @@ -1,131 +0,0 @@ -package vm - -import ( - "math/big" - "strconv" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" -) - -const ( - CALL_TYP = "call" - CALLCODE_TYP = "callcode" - DELEGATECALL_TYP = "delegatecall" - STATICCAL_TYP = "staticcall" - CREATE_TYP = "create" - CREATE2_TYP = "create2" - SUICIDE_TYP = "suicide" -) - -type InnerTxMeta struct { - index int - lastDepth int - indexMap map[int]int - InnerTxs []*types.InnerTx -} - -func (evm *EVM) GetInnerTxMeta() *InnerTxMeta { - return evm.innerTxMeta -} - -func (evm *EVM) AddInnerTx(innerTx *types.InnerTx) { - evm.innerTxMeta.InnerTxs = append(evm.innerTxMeta.InnerTxs, innerTx) -} - -func (evm *EVM) PopInnerTxs() []*types.InnerTx { - innertxs := make([]*types.InnerTx, len(evm.innerTxMeta.InnerTxs)) - copy(innertxs, evm.innerTxMeta.InnerTxs) - - evm.innerTxMeta.InnerTxs = evm.innerTxMeta.InnerTxs[:0] - evm.innerTxMeta.index = 0 - evm.innerTxMeta.lastDepth = 0 - // Clear the index map - for k := range evm.innerTxMeta.indexMap { - delete(evm.innerTxMeta.indexMap, k) - } - return innertxs -} - -func beforeOp( - evm *EVM, - callTyp string, - fromAddr common.Address, - toAddr *common.Address, - codeAddr *common.Address, - input []byte, - gas uint64, - value *big.Int) (*types.InnerTx, int) { - innerTx := &types.InnerTx{ - CallType: callTyp, - From: fromAddr.String(), - ValueWei: value.String(), - CallValueWei: hexutil.EncodeBig(value), - Gas: gas, - IsError: false, - } - - if toAddr != nil { - innerTx.To = toAddr.String() - } - if codeAddr != nil { - innerTx.CodeAddress = codeAddr.String() - } - - if input != nil { - innerTx.Input = hexutil.Encode(input) - } - - innerTxMeta := evm.GetInnerTxMeta() - depth := evm.depth - if depth == innerTxMeta.lastDepth { - innerTxMeta.index++ - innerTxMeta.indexMap[depth] = innerTxMeta.index - } else if depth < innerTxMeta.lastDepth { - innerTxMeta.index = innerTxMeta.indexMap[depth] + 1 - innerTxMeta.indexMap[depth] = innerTxMeta.index - innerTxMeta.lastDepth = depth - } else if depth > innerTxMeta.lastDepth { - innerTxMeta.index = 0 - innerTxMeta.indexMap[depth] = 0 - innerTxMeta.lastDepth = depth - } - for i := 1; i <= innerTxMeta.lastDepth; i++ { - innerTx.Name = innerTx.Name + "_" + strconv.Itoa(innerTxMeta.indexMap[i]) - } - innerTx.Name = innerTx.CallType + innerTx.Name - innerTx.Dept = *big.NewInt(int64(depth)) - innerTx.InternalIndex = *big.NewInt(int64(innerTxMeta.index)) - - evm.AddInnerTx(innerTx) - - newIndex := len(evm.GetInnerTxMeta().InnerTxs) - 1 - if newIndex < 0 { - newIndex = 0 - } - - return innerTx, newIndex -} - -func afterOp(evm *EVM, opType string, gas_used uint64, newIndex int, innerTx *types.InnerTx, addr *common.Address, err error, ret []byte) { - innerTx.GasUsed = gas_used - if ret != nil { - innerTx.Output = hexutil.Encode(ret[:]) - } - if err != nil { - innerTx.Error = err.Error() - innerTx.IsError = true - innerTxMeta := evm.GetInnerTxMeta() - for _, tx := range innerTxMeta.InnerTxs[newIndex:] { - tx.IsError = true - } - } - - switch opType { - case CREATE_TYP, CREATE2_TYP: - if addr != nil { - innerTx.To = addr.String() - } - } -} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9770c6a53c..07072a48a4 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -18,10 +18,8 @@ package vm import ( "math" - "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -673,9 +671,7 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - innerTx, newIndex := beforeOp(evm, CREATE_TYP, scope.Contract.Address(), nil, nil, input, gas, value.ToBig()) res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value) - afterOp(evm, CREATE_TYP, gas-returnGas, newIndex, innerTx, &addr, suberr, res) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only @@ -717,10 +713,8 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - innerTx, newIndex := beforeOp(evm, CREATE2_TYP, scope.Contract.Address(), nil, nil, input, gas, endowment.ToBig()) res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, &endowment, &salt) - afterOp(evm, CREATE2_TYP, gas-returnGas, newIndex, innerTx, &addr, suberr, res) // Push item on the stack based on the returned error. if suberr != nil { @@ -758,9 +752,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas += params.CallStipend } - innerTx, newIndex := beforeOp(evm, CALL_TYP, scope.Contract.Address(), &toAddr, nil, args, gas, value.ToBig()) ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) - afterOp(evm, CALL_TYP, gas-returnGas, newIndex, innerTx, nil, err, ret) if err != nil { temp.Clear() @@ -794,9 +786,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas += params.CallStipend } - innerTx, newIndex := beforeOp(evm, CALLCODE_TYP, scope.Contract.Address(), &toAddr, &toAddr, args, gas, value.ToBig()) ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) - afterOp(evm, CALLCODE_TYP, gas-returnGas, newIndex, innerTx, nil, err, ret) if err != nil { temp.Clear() @@ -826,15 +816,8 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - innerTx, newIndex := beforeOp(evm, DELEGATECALL_TYP, scope.Contract.Address(), &toAddr, nil, args, gas, big.NewInt(0)) ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) - // For X Layer - innerTx.TraceAddress = scope.Contract.Address().String() - innerTx.ValueWei = scope.Contract.value.ToBig().String() - innerTx.CallValueWei = hexutil.EncodeBig(scope.Contract.value.ToBig()) - afterOp(evm, DELEGATECALL_TYP, gas-returnGas, newIndex, innerTx, nil, err, ret) - if err != nil { temp.Clear() } else { @@ -862,11 +845,9 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - innerTx, newIndex := beforeOp(evm, STATICCAL_TYP, scope.Contract.Address(), &toAddr, nil, args, gas, big.NewInt(0)) ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) - afterOp(evm, STATICCAL_TYP, gas-returnGas, newIndex, innerTx, nil, err, ret) - if err != nil { + if err != nil{ temp.Clear() } else { temp.SetOne() @@ -911,11 +892,8 @@ func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } beneficiary := scope.Stack.pop() balance := evm.StateDB.GetBalance(scope.Contract.Address()) - beneficiaryAddr := common.Address(beneficiary.Bytes20()) - innerTx, newIndex := beforeOp(evm, SUICIDE_TYP, scope.Contract.Address(), &beneficiaryAddr, nil, nil, 0, balance.ToBig()) evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) evm.StateDB.SelfDestruct(scope.Contract.Address()) - afterOp(evm, SUICIDE_TYP, 0, newIndex, innerTx, nil, nil, nil) if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index c4396c8014..1fb0165db2 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -42,10 +42,7 @@ type Config struct { PrecompileOverrides PrecompileOverrides // Precompiles can be swapped / changed / wrapped as needed NoMaxCodeSize bool // Ignore Max code size and max init code size limits - CallerOverride func(v common.Address) common.Address // Swap the caller as needed, for VM prank functionality. - - // For X Layer - EnableInnerTxs bool // Calculate inner txs + CallerOverride func(v common.Address) common.Address // Swap the caller as needed, for VM prank functionality. } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/api_backend.go b/eth/api_backend.go index 71ddd6d943..d13ebfe1e7 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -61,12 +61,6 @@ func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { return b.eth.blockchain.Config() } -// For X Layer -// IsInnerTxEnabled returns whether inner transaction capture is enabled. -func (b *EthAPIBackend) IsInnerTxEnabled() bool { - return b.eth.config.XLayer.EnableInnerTx -} - func (b *EthAPIBackend) CurrentBlock() *types.Header { return b.eth.blockchain.CurrentBlock() } diff --git a/eth/api_legacy_xlayer.go b/eth/api_legacy_xlayer.go index cd493e4122..0c19d512df 100644 --- a/eth/api_legacy_xlayer.go +++ b/eth/api_legacy_xlayer.go @@ -109,16 +109,14 @@ func (api *XlayerHybridBlockChainAPI) shouldProxy(ctx context.Context, bNrOrHash // XlayerHybridBlockChainAPI wraps the standard BlockChainAPI to add migration routing type XlayerHybridBlockChainAPI struct { *ethapi.BlockChainAPI - txPreExecAPI *TxPreExecAPI - legacyRpc *XlayerLegacyRPCService + legacyRpc *XlayerLegacyRPCService } // NewXlayerHybridBlockChainAPI creates a new migration-aware BlockChainAPI -func NewXlayerHybridBlockChainAPI(original *ethapi.BlockChainAPI, txPreExecAPI *TxPreExecAPI, legacyRPCService *XlayerLegacyRPCService) *XlayerHybridBlockChainAPI { +func NewXlayerHybridBlockChainAPI(original *ethapi.BlockChainAPI, legacyRPCService *XlayerLegacyRPCService) *XlayerHybridBlockChainAPI { return &XlayerHybridBlockChainAPI{ BlockChainAPI: original, legacyRpc: legacyRPCService, - txPreExecAPI: txPreExecAPI, } } @@ -352,32 +350,10 @@ func (api *XlayerHybridBlockChainAPI) GetCode(ctx context.Context, address commo return api.BlockChainAPI.GetCode(ctx, address, blockNrOrHash) } -// eth_transactionPreExec FORWARD -func (api *XlayerHybridBlockChainAPI) TransactionPreExec(ctx context.Context, origins []PreArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) ([]PreResult, error) { - if api.txPreExecAPI == nil { - return nil, fmt.Errorf("TxPreExecAPI not available") - } - - bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - if blockNrOrHash != nil { - bNrOrHash = *blockNrOrHash - } - - shouldProxy := api.shouldProxy(ctx, &bNrOrHash) - if shouldProxy { - var result []PreResult - err := api.legacyRpc.ErigonClient.CallContext(ctx, &result, "eth_transactionPreExec", origins, &bNrOrHash, stateOverrides) - return result, err - } - - return api.txPreExecAPI.TransactionPreExec(ctx, origins, &bNrOrHash, stateOverrides) -} - // XlayerHybridTransactionAPI wraps the standard TransactionAPI to add migration routing type XlayerHybridTransactionAPI struct { *ethapi.TransactionAPI - TxPreExecAPI *TxPreExecAPI - legacyRpc *XlayerLegacyRPCService + legacyRpc *XlayerLegacyRPCService } // NewXlayerHybridTransactionAPI creates a new migration-aware TransactionAPI @@ -442,34 +418,6 @@ func (api *XlayerHybridTransactionAPI) GetBlockTransactionCountByNumber(ctx cont return api.TransactionAPI.GetBlockTransactionCountByNumber(ctx, blockNr) } -// eth_getBlockInternalTransactions FORWARD -func (api *XlayerHybridTransactionAPI) GetBlockInternalTransactions(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Hash][]*types.InnerTx, error) { - // Check if we should proxy to erigon - if api.legacyRpc.shouldProxyByNumber(blockNr) { - var result map[common.Hash][]*types.InnerTx - err := api.legacyRpc.ErigonClient.CallContext(ctx, &result, "eth_getBlockInternalTransactions", hexutil.Uint64(blockNr)) - return result, err - } - // Handle locally - return api.TransactionAPI.GetBlockInternalTransactions(ctx, blockNr) -} - -// eth_getInternalTransactions TransactionAPI LOCAL -func (api *XlayerHybridTransactionAPI) GetInternalTransactions(ctx context.Context, txHash common.Hash) ([]*types.InnerTx, error) { - // Check if the transaction exists locally - tx, err := api.TransactionAPI.GetTransactionByHash(ctx, txHash) - - // If transaction doesn't exist locally, try Erigon - if tx == nil || err != nil { - var remoteResult []*types.InnerTx - err := api.legacyRpc.ErigonClient.CallContext(ctx, &remoteResult, "eth_getInternalTransactions", txHash) - return remoteResult, err - } - - // Transaction exists locally - return api.TransactionAPI.GetInternalTransactions(ctx, txHash) -} - // eth_getRawTransactionByBlockHashAndIndex TransactionAPI LOCAL func (api *XlayerHybridTransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { // Try local first @@ -792,7 +740,7 @@ func (api *XlayerHybridFilterAPI) Logs(ctx context.Context, crit filters.FilterC } // WrapAPIsForXlayer wraps the standard APIs with migration-aware versions -func WrapAPIsForXlayer(apis []rpc.API, txPreExecAPI *TxPreExecAPI, config *XlayerLegacyRPCService) []rpc.API { +func WrapAPIsForXlayer(apis []rpc.API, config *XlayerLegacyRPCService) []rpc.API { if config == nil { return apis // No migration configured, return original APIs } @@ -809,7 +757,7 @@ func WrapAPIsForXlayer(apis []rpc.API, txPreExecAPI *TxPreExecAPI, config *Xlaye wrapped = append(wrapped, rpc.API{ Namespace: api.Namespace, Version: api.Version, - Service: NewXlayerHybridBlockChainAPI(original, txPreExecAPI, config), + Service: NewXlayerHybridBlockChainAPI(original, config), Public: api.Public, Authenticated: api.Authenticated, }) diff --git a/eth/api_legacy_xlayer_test.go b/eth/api_legacy_xlayer_test.go index a946366974..e85449e364 100644 --- a/eth/api_legacy_xlayer_test.go +++ b/eth/api_legacy_xlayer_test.go @@ -341,84 +341,6 @@ func (s *mockErigonService) EstimateGas(args map[string]interface{}, blockNrOrHa return hexutil.Uint64(21000), nil } -// TransactionPreExec mocks eth_transactionPreExec and returns mock pre-execution results -func (s *mockErigonService) TransactionPreExec(origins []PreArgs, blockNrOrHash interface{}, stateOverrides interface{}) ([]PreResult, error) { - results := make([]PreResult, len(origins)) - for i := range origins { - results[i] = PreResult{ - InnerTxs: []interface{}{}, - Logs: []interface{}{}, - StateDiff: map[string]interface{}{ - "0x1234567890123456789012345678901234567890": map[string]interface{}{ - "before": "0x3b9aca00", - "after": "0x3b99f4b8", - }, - }, - GasUsed: 21000, - } - } - return results, nil -} - -// mockTxPreExecAPI is a mock implementation for local execution -type mockTxPreExecAPI struct { - results map[uint64][]PreResult - hashFails bool - knownHash common.Hash -} - -func (m *mockTxPreExecAPI) TransactionPreExec(ctx context.Context, origins []PreArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) ([]PreResult, error) { - if blockNr, ok := blockNrOrHash.Number(); ok { - if results, exists := m.results[uint64(blockNr)]; exists { - return results, nil - } - return nil, fmt.Errorf("no results for block %d", blockNr) - } - - if blockHash, ok := blockNrOrHash.Hash(); ok { - if m.hashFails && blockHash != m.knownHash { - return nil, fmt.Errorf("block hash not found: %s", blockHash.Hex()) - } - if results, exists := m.results[0]; exists { - return results, nil - } - } - - return nil, fmt.Errorf("no results available") -} - -// mockTxPreExecAPIWrapper wraps the routing logic for testing -type mockTxPreExecAPIWrapper struct { - mock *mockTxPreExecAPI - legacyRpc *XlayerLegacyRPCService -} - -func (w *mockTxPreExecAPIWrapper) TransactionPreExec(ctx context.Context, origins []PreArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) ([]PreResult, error) { - bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - if blockNrOrHash != nil { - bNrOrHash = *blockNrOrHash - } - - // Route by block number - if blockNr, ok := bNrOrHash.Number(); ok && blockNr >= 0 { - if w.legacyRpc.shouldProxyByNumber(blockNr) { - var result []PreResult - err := w.legacyRpc.ErigonClient.CallContext(ctx, &result, "eth_transactionPreExec", origins, &bNrOrHash, stateOverrides) - return result, err - } - return w.mock.TransactionPreExec(ctx, origins, &bNrOrHash, stateOverrides) - } - - localResult, err := w.mock.TransactionPreExec(ctx, origins, &bNrOrHash, stateOverrides) - if err == nil && localResult != nil { - return localResult, nil - } - - var result []PreResult - err = w.legacyRpc.ErigonClient.CallContext(ctx, &result, "eth_transactionPreExec", origins, &bNrOrHash, stateOverrides) - return result, err -} - // createMockErigonServer creates an httptest server that simulates an Erigon RPC endpoint func createMockErigonServer(t *testing.T) (*httptest.Server, *mockErigonService) { service := newMockErigonService() @@ -602,7 +524,7 @@ func TestHybridBlockChainAPI_ProxiesGetStorageAt(t *testing.T) { } defer legacy.Close() - api := NewXlayerHybridBlockChainAPI(nil, nil, legacy) + api := NewXlayerHybridBlockChainAPI(nil, legacy) // Test that we can call Erigon to get storage ctx := context.Background() @@ -1634,7 +1556,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { }, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -1668,7 +1590,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { }, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -1693,7 +1615,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { }, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -1715,7 +1637,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { }, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -1740,7 +1662,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { }, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -1760,7 +1682,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { {Namespace: "debug", Service: &struct{}{}, Public: false}, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, legacy) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, legacy) if len(wrappedAPIs) != 5 { t.Fatalf("expected 5 APIs, got %d", len(wrappedAPIs)) } @@ -1792,7 +1714,7 @@ func TestWrapAPIsForXlayer(t *testing.T) { {Namespace: "eth", Service: ðapi.BlockChainAPI{}, Public: true}, } - wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil, nil) + wrappedAPIs := WrapAPIsForXlayer(originalAPIs, nil) if len(wrappedAPIs) != 1 { t.Fatalf("expected 1 API, got %d", len(wrappedAPIs)) } @@ -2250,7 +2172,7 @@ func TestNilLegacyService(t *testing.T) { {Namespace: "eth", Service: originalAPI, Public: true}, } - wrapped := WrapAPIsForXlayer(apis, nil, nil) + wrapped := WrapAPIsForXlayer(apis, nil) if len(wrapped) != 1 { t.Fatalf("expected 1 API, got %d", len(wrapped)) } @@ -2316,191 +2238,3 @@ func TestInvalidBlockRanges(t *testing.T) { }) } -// Test XlayerHybridTxPreExecAPI routing for TransactionPreExec -func TestHybridTxPreExecAPI_RoutingByBlockNumber(t *testing.T) { - t.Parallel() - - // Setup mock Erigon server - legacy, server, _ := createTestLegacyService(t, 100) - defer server.Close() - defer legacy.Close() - - // Create a mock local TxPreExecAPI - mockLocal := &mockTxPreExecAPI{ - results: make(map[uint64][]PreResult), - } - - // Add local results for blocks >= 100 - mockLocal.results[100] = []PreResult{ - { - InnerTxs: []interface{}{}, - Logs: []interface{}{}, - StateDiff: map[string]interface{}{ - "0xLOCAL": map[string]interface{}{ - "before": "0x1388", - "after": "0x1377", - }, - }, - GasUsed: 21000, - }, - } - mockLocal.results[150] = mockLocal.results[100] - - // Create hybrid API with wrapper - wrapperAPI := &mockTxPreExecAPIWrapper{ - mock: mockLocal, - legacyRpc: legacy, - } - - ctx := context.Background() - sender := common.HexToAddress("0xSender") - receiver := common.HexToAddress("0xReceiver") - gas := hexutil.Uint64(21000) - testArgs := []PreArgs{ - { - From: &sender, - To: &receiver, - Gas: &gas, - GasPrice: (*hexutil.Big)(big.NewInt(1000000000)), - Value: (*hexutil.Big)(big.NewInt(1000000000000000000)), - }, - } - - t.Run("Block below migration routes to Erigon", func(t *testing.T) { - blockNum := rpc.BlockNumber(50) - blockNrOrHash := rpc.BlockNumberOrHashWithNumber(blockNum) - - results, err := wrapperAPI.TransactionPreExec(ctx, testArgs, &blockNrOrHash, nil) - if err != nil { - t.Fatalf("TransactionPreExec failed: %v", err) - } - if len(results) != 1 { - t.Fatalf("expected 1 result, got %d", len(results)) - } - - // Verify it came from Erigon - stateDiff, ok := results[0].StateDiff.(map[string]interface{}) - if !ok { - t.Fatal("expected StateDiff to be map[string]interface{}") - } - if _, ok := stateDiff["0x1234567890123456789012345678901234567890"]; !ok { - t.Error("expected state diff from Erigon mock") - } - t.Log("Successfully fell back to Erigon, stateDiff: ", stateDiff) - }) - - t.Run("Block at migration threshold routes to local", func(t *testing.T) { - blockNum := rpc.BlockNumber(100) - blockNrOrHash := rpc.BlockNumberOrHashWithNumber(blockNum) - - results, err := wrapperAPI.TransactionPreExec(ctx, testArgs, &blockNrOrHash, nil) - if err != nil { - t.Fatalf("TransactionPreExec failed: %v", err) - } - if len(results) != 1 { - t.Fatalf("expected 1 result, got %d", len(results)) - } - - stateDiff, ok := results[0].StateDiff.(map[string]interface{}) - if !ok { - t.Fatal("expected StateDiff to be map[string]interface{}") - } - if _, ok := stateDiff["0xLOCAL"]; !ok { - t.Error("expected state diff from local mock") - } - t.Log("Successfully fell back to local, stateDiff: ", stateDiff) - }) - - t.Run("Block above migration routes to local", func(t *testing.T) { - blockNum := rpc.BlockNumber(150) - blockNrOrHash := rpc.BlockNumberOrHashWithNumber(blockNum) - - results, err := wrapperAPI.TransactionPreExec(ctx, testArgs, &blockNrOrHash, nil) - if err != nil { - t.Fatalf("TransactionPreExec failed: %v", err) - } - if len(results) != 1 { - t.Fatalf("expected 1 result, got %d", len(results)) - } - - // Verify it came from local - stateDiff, ok := results[0].StateDiff.(map[string]interface{}) - if !ok { - t.Fatal("expected StateDiff to be map[string]interface{}") - } - if _, ok := stateDiff["0xLOCAL"]; !ok { - t.Error("expected state diff from local mock") - } - t.Log("Successfully fell back to local, stateDiff: ", stateDiff) - }) -} - -// Test XlayerHybridTxPreExecAPI routing for block hash -func TestHybridTxPreExecAPI_RoutingByBlockHash(t *testing.T) { - t.Parallel() - - // Setup mock Erigon server - legacy, server, _ := createTestLegacyService(t, 100) - defer server.Close() - defer legacy.Close() - - mockLocal := &mockTxPreExecAPI{ - results: make(map[uint64][]PreResult), - hashFails: true, - knownHash: common.HexToHash("0xLOCAL_HASH"), - } - - mockLocal.results[0] = []PreResult{ - { - InnerTxs: []interface{}{}, - Logs: []interface{}{}, - StateDiff: map[string]interface{}{ - "0xLOCAL": map[string]interface{}{ - "before": "0x1388", - "after": "0x1377", - }, - }, - GasUsed: 21000, - }, - } - - wrapperAPI := &mockTxPreExecAPIWrapper{ - mock: mockLocal, - legacyRpc: legacy, - } - - ctx := context.Background() - sender := common.HexToAddress("0xSender") - receiver := common.HexToAddress("0xReceiver") - gas := hexutil.Uint64(21000) - testArgs := []PreArgs{ - { - From: &sender, - To: &receiver, - Gas: &gas, - GasPrice: (*hexutil.Big)(big.NewInt(1000000000)), - Value: (*hexutil.Big)(big.NewInt(1000000000000000000)), - }, - } - - t.Run("BlockHash test", func(t *testing.T) { - blockHash := mockLocal.knownHash - blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) - - results, err := wrapperAPI.TransactionPreExec(ctx, testArgs, &blockNrOrHash, nil) - if err != nil { - t.Fatalf("TransactionPreExec failed: %v", err) - } - if len(results) != 1 { - t.Fatalf("expected 1 result, got %d", len(results)) - } - - stateDiff, ok := results[0].StateDiff.(map[string]interface{}) - if !ok { - t.Fatal("expected StateDiff to be map[string]interface{}") - } - if _, ok := stateDiff["0xLOCAL"]; !ok { - t.Error("expected state diff from local mock") - } - }) -} diff --git a/eth/api_pre_exec_xlayer.go b/eth/api_pre_exec_xlayer.go deleted file mode 100644 index 4a6a29a514..0000000000 --- a/eth/api_pre_exec_xlayer.go +++ /dev/null @@ -1,663 +0,0 @@ -package eth - -import ( - "context" - "encoding/json" - "fmt" - "math/big" - "math/rand" - "strings" - "time" - - coreState "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/internal/ethapi/override" - "github.com/ethereum/go-ethereum/rpc" - "github.com/google/uuid" -) - -const ( - UnKnownErrCode = 1000 - InsufficientBalanceErrCode = 1001 - RevertedErrCode = 1002 - CheckPreArgsErrCode = 1003 - - MaxGasLimit = 30000000 -) - -// PreExecInnerTx defines the structure for inner transactions returned by TransactionPreExec RPC -// This is specifically designed for the eth_transaction_preexec endpoint -type PreExecInnerTx struct { - Dept big.Int `json:"dept"` - InternalIndex big.Int `json:"internal_index"` - CallType string `json:"call_type"` - Name string `json:"name"` - TraceAddress string `json:"trace_address"` - CodeAddress string `json:"code_address"` - From string `json:"from"` - To string `json:"to"` - Input string `json:"input"` - Output string `json:"output"` - IsError bool `json:"is_error"` - GasUsed uint64 `json:"gas_used"` - Value string `json:"value"` - ValueWei string `json:"value_wei"` - Error string `json:"error"` - ReturnGas uint64 `json:"return_gas"` -} - -type PreArgs struct { - ChainId *big.Int `json:"chainId,omitempty"` - From *common.Address `json:"from"` - To *common.Address `json:"to"` - Gas *hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` - Value *hexutil.Big `json:"value"` - Nonce *hexutil.Uint64 `json:"nonce"` - Data *hexutil.Bytes `json:"data"` - Input *hexutil.Bytes `json:"input"` - AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"` -} - -type CallTracerResult struct { - Calls []CallTracerResult `json:"calls"` - From string `json:"from"` - Gas string `json:"gas"` - GasUsed string `json:"gasUsed"` - Input string `json:"input"` - Output string `json:"output,omitempty"` - To string `json:"to"` - Type string `json:"type"` - Value string `json:"value"` - Error string `json:"error,omitempty"` - RevertReason string `json:"revertReason,omitempty"` -} - -type StateAccount struct { - Balance string `json:"balance"` - Code string `json:"code"` - Nonce uint64 `json:"nonce"` - Storage map[string]string `json:"storage"` -} - -type PreError struct { - Code int `json:"code"` - Msg string `json:"msg"` -} - -func (args PreArgs) ToLogString() string { - argsBytes, _ := json.Marshal(args) - return string(argsBytes) -} - -func toPreError(err error, result *core.ExecutionResult) PreError { - preErr := PreError{ - Code: UnKnownErrCode, - } - if err != nil { - preErr.Msg = err.Error() - } - if result != nil && result.Err != nil { - preErr.Msg = result.Err.Error() - } - if strings.HasPrefix(preErr.Msg, "execution reverted") { - preErr.Code = RevertedErrCode - if result != nil { - preErr.Msg, _ = abi.UnpackRevert(result.Revert()) - } - } - if strings.HasPrefix(preErr.Msg, "out of gas") { - preErr.Code = RevertedErrCode - } - if strings.HasPrefix(preErr.Msg, "insufficient funds for transfer") { - preErr.Code = InsufficientBalanceErrCode - } - if strings.HasPrefix(preErr.Msg, "insufficient balance for transfer") { - preErr.Code = InsufficientBalanceErrCode - } - if strings.HasPrefix(preErr.Msg, "insufficient funds for gas * price") { - preErr.Code = InsufficientBalanceErrCode - } - return preErr -} - -type PreResult struct { - InnerTxs interface{} `json:"innerTxs"` - Logs interface{} `json:"logs"` - StateDiff interface{} `json:"stateDiff"` - Error PreError `json:"error"` - GasUsed uint64 `json:"gasUsed"` - BlockNumber *big.Int `json:"blockNumber"` -} - -func (res PreResult) ToLogString() string { - // spilt InnerTxs - innerTxsStr, err := json.Marshal(res.InnerTxs) - if err == nil { - innerTxs := make([]*PreExecInnerTx, 0) - if err := json.Unmarshal(innerTxsStr, &innerTxs); err == nil { - if len(innerTxs) > 0 { - innerTx := innerTxs[0] - if len(innerTx.Input) > 100 { - innerTx.Input = innerTx.Input[0:100] - } - if len(innerTx.Output) > 100 { - innerTx.Output = innerTx.Output[0:100] - } - res.InnerTxs = append([]*PreExecInnerTx{}, innerTx) - } - } - } - // spilt Logs - logsStr, err := json.Marshal(res.Logs) - if err == nil { - logs := make([]types.Log, 0) - if err := json.Unmarshal(logsStr, &logs); err == nil { - if len(logs) > 0 { - l := logs[0] - if len(l.Data) > 100 { - l.Data = l.Data[0:100] - } - res.Logs = append([]types.Log{}, l) - } - } - } - resBytes, _ := json.Marshal(res) - return string(resBytes) -} - -func toPreResult(innerTxs []*PreExecInnerTx, logs []*types.Log, stateDiff map[string]interface{}, - preError PreError, gasUsed uint64, number *big.Int) PreResult { - preResult := PreResult{ - Error: preError, - GasUsed: gasUsed, - BlockNumber: number, - } - if len(innerTxs) > 0 { - preResult.InnerTxs = innerTxs - } else { - preResult.InnerTxs = make([]PreExecInnerTx, 0) - } - if len(logs) > 0 { - preResult.Logs = logs - } else { - preResult.Logs = make([]types.Log, 0) - } - if len(stateDiff) > 0 { - preResult.StateDiff = stateDiff - } else { - preResult.StateDiff = make(map[string]interface{}, 0) - } - - return preResult -} - -// TxPreExecAPI is the collection of Ethereum full node related APIs for transaction pre exec. -type TxPreExecAPI struct { - eth *Ethereum -} - -// NewTxPreExecAPI creates a new instance of TxPreExecAPI. -func NewTxPreExecAPI(eth *Ethereum) *TxPreExecAPI { - return &TxPreExecAPI{eth: eth} -} - -func (api *TxPreExecAPI) TransactionPreExec(ctx context.Context, origins []PreArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) ([]PreResult, error) { - start := time.Now() - // gen requestID - requestID := uuid.NewString() - defer func(s time.Time, id string) { - log.Info("Executing TransactionPreExec call finished", "requestID", id, "runtime", time.Since(s)) - }(start, requestID) - preResList := make([]PreResult, 0) - - bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - if blockNrOrHash != nil { - bNrOrHash = *blockNrOrHash - } - state, header, err := api.eth.APIBackend.StateAndHeaderByNumberOrHash(ctx, bNrOrHash) - - if state == nil || err != nil { - return nil, err - } - if stateOverrides != nil { - err = stateOverrides.Apply(state, nil) - if err != nil { - return nil, err - } - } - blockNumber := big.NewInt(0).Set(header.Number) - - for i, origin := range origins { - // Setup context with timeout for each individual transaction - // ETH RPC EVM Timeout default 5s per transaction - timeout := api.eth.APIBackend.RPCEVMTimeout() - txCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - var gasUsed uint64 - log.Info("TransactionPreExec", "requestID", requestID, "input index", i, "input args", origin.ToLogString()) - - var prevArg *PreArgs - if i > 0 { - prevArg = &origins[i-1] - } - correctedGas, err := preArgsCheck(state, origin, prevArg, i) - if err != nil { - preError := PreError{ - Code: CheckPreArgsErrCode, - Msg: err.Error(), - } - preResult := toPreResult(nil, nil, nil, preError, gasUsed, blockNumber) - preResList = append(preResList, preResult) - continue - } - - if correctedGas != nil { - origin.Gas = correctedGas - } - - rawRes, gasUsed, receipt, err := applyMessageWithTracer(txCtx, api, state, origin, header, i, timeout) - if err != nil { - log.Error("TransactionPreExec: applyMessageWithTracer failed", "requestID", requestID, "input args", origin.ToLogString(), "error", err.Error()) - preError := toPreError(err, nil) - preResult := toPreResult(nil, nil, nil, preError, gasUsed, blockNumber) - preResList = append(preResList, preResult) - continue - } - - txHash := common.BigToHash(big.NewInt(int64(i))) - - preRes, err := processTracerResults(rawRes, state, txHash, header, receipt, gasUsed, blockNumber) - if err != nil { - log.Error("TransactionPreExec: processTracerResults failed", "requestID", requestID, "input args", origin.ToLogString(), "error", err.Error()) - preError := toPreError(err, nil) - preResult := toPreResult(nil, nil, nil, preError, gasUsed, blockNumber) - preResList = append(preResList, preResult) - continue - } - - preResList = append(preResList, preRes) - log.Info("TransactionPreExec execute finished", "requestID", requestID, "input index", i, "result", preRes.ToLogString(), "runtime", time.Since(start)) - } - return preResList, nil -} - -func convertCallTracerResultToInnerTxs(traceResult interface{}) (result []*PreExecInnerTx, err error) { - if traceResult == nil { - return nil, fmt.Errorf("call tracer result is nil") - } - - traceResultStr, err := json.Marshal(traceResult) - if err != nil { - return nil, err - } - callTx := CallTracerResult{} - if err := json.Unmarshal(traceResultStr, &callTx); err != nil { - return nil, err - } - - result = make([]*PreExecInnerTx, 0) - convertCallToInnerTxsRecursive(callTx, 0, 0, "", false, &result) - return -} - -// convertCallToInnerTxsRecursive recursively converts a CallTracerResult and all its nested calls to PreExecInnerTx -func convertCallToInnerTxsRecursive(callTx CallTracerResult, depth int64, index int64, depthIndexRoot string, parentError bool, result *[]*PreExecInnerTx) { - isError := parentError - var errorMsg string - if callTx.Error != "" { - isError = true - errorMsg = callTx.Error - } - if callTx.Error != "" && callTx.RevertReason != "" { - isError = true - errorMsg = fmt.Sprintf("%s,%s", callTx.Error, callTx.RevertReason) - } - - gasUsed := new(big.Int) - if len(callTx.GasUsed) > 2 && strings.HasPrefix(callTx.GasUsed, "0x") { - gasUsed, _ = gasUsed.SetString(callTx.GasUsed[2:], 16) - } - - gas := new(big.Int) - if len(callTx.Gas) > 2 && strings.HasPrefix(callTx.Gas, "0x") { - gas, _ = gas.SetString(callTx.Gas[2:], 16) - } - - valueWei := "" - if len(callTx.Value) > 2 && strings.HasPrefix(callTx.Value, "0x") { - valueWeiInt := new(big.Int) - valueWeiInt, _ = valueWeiInt.SetString(callTx.Value[2:], 16) - valueWei = valueWeiInt.String() - } - - gasUint64 := gas.Uint64() - gasUsedUint64 := gasUsed.Uint64() - returnGas := uint64(0) - if gasUint64 > gasUsedUint64 { - returnGas = gasUint64 - gasUsedUint64 - } - - // Handle empty output - ensure it's "0x" instead of "" - output := callTx.Output - if output == "" { - output = "0x" - } - - // Create inner transaction - innerTx := &PreExecInnerTx{ - Dept: *big.NewInt(depth), - InternalIndex: *big.NewInt(index), - CallType: strings.ToLower(callTx.Type), - TraceAddress: "", - CodeAddress: "", - From: common.HexToAddress(callTx.From).Hex(), - To: common.HexToAddress(callTx.To).Hex(), - Input: callTx.Input, - Output: output, - IsError: isError, - GasUsed: gasUsedUint64, - Value: valueWei, - ValueWei: valueWei, - Error: errorMsg, - ReturnGas: returnGas, - } - - // Handle root vs nested call differences - isRoot := depth == 0 - if isRoot { - innerTx.Name = strings.ToLower(callTx.Type) - } else { - if len(callTx.From) > 2 && strings.HasPrefix(callTx.From, "0x") { - innerTx.From = "0x000000000000000000000000" + callTx.From[2:] - } - if len(callTx.To) > 2 && strings.HasPrefix(callTx.To, "0x") { - innerTx.To = "0x000000000000000000000000" + callTx.To[2:] - } - - if strings.ToLower(callTx.Type) == "callcode" { - innerTx.CodeAddress = callTx.To - } - - currentDepthIndexRoot := fmt.Sprintf("%s_%d", depthIndexRoot, index) - innerTx.Name = fmt.Sprintf("%s%s", innerTx.CallType, currentDepthIndexRoot) - } - - // Add current transaction to result - *result = append(*result, innerTx) - - // Recursively process nested calls - if len(callTx.Calls) > 0 { - for i, nestedCall := range callTx.Calls { - var nestedDepthIndexRoot string - if isRoot { - nestedDepthIndexRoot = "" - } else { - nestedDepthIndexRoot = fmt.Sprintf("%s_%d", depthIndexRoot, index) - } - convertCallToInnerTxsRecursive(nestedCall, depth+1, int64(i), nestedDepthIndexRoot, innerTx.IsError, result) - } - } -} - -func convertPrestateTracerResultToStateDiff(traceResult interface{}) (result map[string]interface{}, err error) { - if traceResult == nil { - return nil, fmt.Errorf("prestate tracer result is nil") - } - result = make(map[string]interface{}) - stateDiffResultStr, err := json.Marshal(traceResult) - if err != nil { - return nil, err - } - stateAccount := make(map[string]map[common.Address]*StateAccount) - if err := json.Unmarshal(stateDiffResultStr, &stateAccount); err != nil { - return nil, err - } - var pre, post map[common.Address]*StateAccount - if preState, exist := stateAccount["pre"]; exist { - pre = preState - } else { - return nil, nil - } - if postState, exist := stateAccount["post"]; exist { - post = postState - } else { - return nil, nil - } - - for addr, postState := range post { - if preState, exist := pre[addr]; exist { - addrMap := make(map[string]interface{}) - preStateBalance, postStateBalance := new(big.Int), new(big.Int) - if strings.HasPrefix(preState.Balance, "0x") { - preStateBalance, _ = big.NewInt(0).SetString(preState.Balance[2:], 16) - } - // post state balance - if strings.HasPrefix(postState.Balance, "0x") { - postStateBalance, _ = big.NewInt(0).SetString(postState.Balance[2:], 16) - } else { - postStateBalance = preStateBalance - } - balance := struct { - Before string `json:"before"` - After string `json:"after"` - }{ - Before: preStateBalance.String(), - After: postStateBalance.String(), - } - addrMap["balance"] = balance - result[addr.String()] = addrMap - } - } - - return -} - -func applyMessageWithTracer(ctx context.Context, api *TxPreExecAPI, state *coreState.StateDB, origin PreArgs, header *types.Header, index int, timeout time.Duration) (json.RawMessage, uint64, *types.Receipt, error) { - // get ChainID from ChainConfig - chainId := api.eth.APIBackend.ChainConfig().ChainID - txArgs := ethapi.TransactionArgs{ - ChainID: (*hexutil.Big)(chainId), - From: origin.From, - To: origin.To, - Gas: origin.Gas, - GasPrice: origin.GasPrice, - MaxFeePerGas: origin.MaxFeePerGas, - MaxPriorityFeePerGas: origin.MaxPriorityFeePerGas, - Value: origin.Value, - Data: origin.Data, - Input: origin.Input, - AuthorizationList: origin.AuthorizationList, - } - - if err := txArgs.CallDefaults(api.eth.APIBackend.RPCGasCap(), header.BaseFee, api.eth.APIBackend.ChainConfig().ChainID); err != nil { - return nil, 0, nil, err - } - - msg := txArgs.ToMessage(header.BaseFee, true) - tx := txArgs.ToTransaction(types.LegacyTxType) - - txHash := common.BigToHash(big.NewInt(int64(index))) - traceConfig := []byte(` - { - "prestateTracer": { - "diffMode": true - }, - "callTracer": null - } - `) - - txctx := &tracers.Context{ - BlockHash: header.Hash(), - BlockNumber: big.NewInt(0).Set(header.Number), - TxIndex: 0, - TxHash: txHash, - } - tracer, err := tracers.DefaultDirectory.New("muxTracer", txctx, traceConfig, api.eth.APIBackend.ChainConfig()) - if err != nil { - return nil, 0, nil, err - } - - hookedState := coreState.NewHookedState(state, tracer.Hooks) - blockContext := core.NewEVMBlockContext(header, api.eth.BlockChain(), nil, api.eth.APIBackend.ChainConfig(), state) - evm := vm.NewEVM(blockContext, hookedState, api.eth.APIBackend.ChainConfig(), vm.Config{NoBaseFee: true, Tracer: tracer.Hooks}) - - // Setup timeout context - timeoutCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - go func() { - <-timeoutCtx.Done() - evm.Cancel() - }() - - evm.Context.BaseFee = big.NewInt(0) - - // blocknumber and time are random to simulate real transactions with propagation delay - evm.Context.BlockNumber.Add(evm.Context.BlockNumber, big.NewInt(rand.Int63n(6)+6)) - evm.Context.Time += uint64(rand.Int63n(60) + 30) - gp := new(core.GasPool).AddGas(MaxGasLimit) - state.SetTxContext(txHash, index) - - var gasUsed uint64 - receipt, err := core.ApplyTransactionWithEVM(msg, gp, state, evm.Context.BlockNumber, txctx.BlockHash, evm.Context.Time, tx, &gasUsed, evm) - if err != nil { - return nil, gasUsed, nil, err - } - - // If the timer caused an abort, return an appropriate error message - if evm.Cancelled() { - return nil, gasUsed, nil, fmt.Errorf("execution aborted (timeout = %v)", timeout) - } - - rawRes, err := tracer.GetResult() - if err != nil { - return nil, gasUsed, nil, err - } - - return rawRes, gasUsed, receipt, nil -} - -func processTracerResults(rawRes json.RawMessage, state *coreState.StateDB, txHash common.Hash, header *types.Header, receipt *types.Receipt, gasUsed uint64, blockNumber *big.Int) (PreResult, error) { - var res map[string]interface{} - if err := json.Unmarshal(rawRes, &res); err != nil { - preError := toPreError(err, nil) - return toPreResult(nil, nil, nil, preError, gasUsed, blockNumber), nil - } - - // convert callTracer result to inner txs - innerTxs := make([]*PreExecInnerTx, 0) - if t, exist := res["callTracer"]; exist { - convertedInnerTxs, err := convertCallTracerResultToInnerTxs(t) - if err != nil { - preError := PreError{ - Code: UnKnownErrCode, - Msg: err.Error(), - } - return toPreResult(nil, nil, nil, preError, gasUsed, blockNumber), nil - } - // innerTxs are set only when there are deep calls (contract to contract calls) or failed calls - hasDeepCalls := false - hasFailedCalls := false - for _, innerTx := range convertedInnerTxs { - if innerTx.Dept.Int64() > 0 { - hasDeepCalls = true - } - if innerTx.IsError || innerTx.Error != "" { - hasFailedCalls = true - } - } - if hasDeepCalls || hasFailedCalls { - innerTxs = convertedInnerTxs - } - } - - // convert prestateTracer result to state diff - stateDiff := make(map[string]interface{}, 0) - if t, exist := res["prestateTracer"]; exist { - var err error - stateDiff, err = convertPrestateTracerResultToStateDiff(t) - if err != nil { - preError := PreError{ - Code: UnKnownErrCode, - Msg: err.Error(), - } - return toPreResult(nil, nil, nil, preError, gasUsed, blockNumber), nil - } - } - - // Create the final result - preRes := toPreResult(innerTxs, state.GetLogs(txHash, header.Number.Uint64(), header.Hash(), header.Time), stateDiff, PreError{}, gasUsed, blockNumber) - - // Handle receipt status failures - if receipt != nil && receipt.Status == types.ReceiptStatusFailed { - preRes.Error = toPreError(nil, nil) - } - - // Handle inner transaction errors - if preRes.Error.Msg == "" && len(innerTxs) != 0 && innerTxs[0].Error != "" { - preRes.Error = PreError{ - Code: RevertedErrCode, - Msg: innerTxs[0].Error, - } - } - - return preRes, nil -} - -func preArgsCheck(state *coreState.StateDB, arg PreArgs, prevArg *PreArgs, index int) (*hexutil.Uint64, error) { - if arg.From == nil { - return nil, fmt.Errorf("from is nil") - } - - if arg.To == nil { - return nil, fmt.Errorf("to is nil") - } - - if arg.Nonce == nil { - return nil, fmt.Errorf("%s, nonce is nil", arg.From.Hex()) - } - - // check whether sender's nonce decreases - if prevArg != nil && *arg.From == *prevArg.From && (uint64)(*arg.Nonce) <= (uint64)(*prevArg.Nonce) { - return nil, fmt.Errorf("%v nonce decreases, tx index %d has nonce %d, tx index %d has nonce %d", - arg.From.Hex(), index-1, (uint64)(*prevArg.Nonce), index, (uint64)(*arg.Nonce)) - } - - msgFrom := *arg.From - msgNonce := uint64(*arg.Nonce) - stNonce := state.GetNonce(msgFrom) - - if stNonce > msgNonce { - return nil, fmt.Errorf("%w: address %v, tx: %d state: %d", core.ErrNonceTooLow, - msgFrom.Hex(), msgNonce, stNonce) - } else if stNonce+1 < stNonce { - return nil, fmt.Errorf("%w: address %v, nonce: %d", core.ErrNonceMax, - msgFrom.Hex(), stNonce) - } - - // check gas, if gas value is 0 or > 30000000, return corrected gas value - if arg.Gas == nil { - gas := uint64(MaxGasLimit) - return (*hexutil.Uint64)(&gas), nil - } else { - gas := uint64(*arg.Gas) - if gas == 0 || gas > uint64(MaxGasLimit) { - gas = uint64(MaxGasLimit) - return (*hexutil.Uint64)(&gas), nil - } - } - - return nil, nil -} diff --git a/eth/backend.go b/eth/backend.go index 788f1ae374..264ae545ae 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -263,8 +263,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { EnablePreimageRecording: config.EnablePreimageRecording, EnableWitnessStats: config.EnableWitnessStats, StatelessSelfValidation: config.StatelessSelfValidation, - // For X Layer - EnableInnerTxs: config.XLayer.EnableInnerTx, }, // Enables file journaling for the trie database. The journal files will be stored // within the data directory. The corresponding paths will be either: @@ -527,17 +525,9 @@ func (s *Ethereum) APIs() []rpc.API { //// Append any APIs exposed explicitly by the consensus engine //apis = append(apis, s.engine.APIs(s.BlockChain())...) - // For XLayer, eth_transactionPreExec - txPreExecAPI := NewTxPreExecAPI(s) - // Xlayer: Wrap APIs with migration routing if configured if s.xlayerLegacyRPCService != nil { - apis = WrapAPIsForXlayer(apis, txPreExecAPI, s.xlayerLegacyRPCService) - } else { - apis = append(apis, rpc.API{ - Namespace: "eth", - Service: txPreExecAPI, - }) + apis = WrapAPIsForXlayer(apis, s.xlayerLegacyRPCService) } // Append any Sequencer APIs as enabled diff --git a/eth/ethconfig/config_xlayer.go b/eth/ethconfig/config_xlayer.go index 8706c66292..7f87e2938f 100644 --- a/eth/ethconfig/config_xlayer.go +++ b/eth/ethconfig/config_xlayer.go @@ -5,7 +5,6 @@ import ( ) var DefaultXLayerConfig = XLayerConfig{ - EnableInnerTx: true, LegacyPp: MigrationConfig{ MigrationBlock: nil, PPRPCUrl: "", @@ -19,8 +18,7 @@ var DefaultXLayerConfig = XLayerConfig{ // XLayerConfig is the X Layer config used on the eth backend type XLayerConfig struct { - EnableInnerTx bool `toml:",omitempty"` - LegacyPp MigrationConfig `toml:",omitempty"` // The erigon RPC endpoint URL for pre-migration blocks + LegacyPp MigrationConfig `toml:",omitempty"` // The erigon RPC endpoint URL for pre-migration blocks Monitor MonitorConfig `toml:",omitempty"` // Transaction monitoring configuration } diff --git a/internal/ethapi/api_xlayer.go b/internal/ethapi/api_xlayer.go deleted file mode 100644 index 28099a2186..0000000000 --- a/internal/ethapi/api_xlayer.go +++ /dev/null @@ -1,66 +0,0 @@ -package ethapi - -import ( - "context" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rpc" -) - -// GetInternalTransactions returns the inner transactions for a given transaction hash -func (api *TransactionAPI) GetInternalTransactions(ctx context.Context, txHash common.Hash) ([]*types.InnerTx, error) { - // Check if inner transaction feature is enabled - if xlayerBackend, ok := api.b.(XLayerBackend); ok && !xlayerBackend.IsInnerTxEnabled() { - return nil, errors.New("unsupported internal transaction method") - } - - innerTxs, err := rawdb.ReadInnerTxsByTxHash(api.b.ChainDb(), txHash) - - if err != nil { - return nil, fmt.Errorf("failed to read inner transactions: %w", err) - } - - if innerTxs == nil { - return []*types.InnerTx{}, nil - } - - return innerTxs, nil -} - -// GetBlockInternalTransactions returns all inner transactions for all transactions in a block -func (api *TransactionAPI) GetBlockInternalTransactions(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Hash][]*types.InnerTx, error) { - // Check if inner transaction feature is enabled - if xlayerBackend, ok := api.b.(XLayerBackend); ok && !xlayerBackend.IsInnerTxEnabled() { - return nil, errors.New("unsupported internal transaction method") - } - - block, err := api.b.BlockByNumber(ctx, blockNr) - if err != nil { - return nil, fmt.Errorf("failed to get block: %w", err) - } - if block == nil { - return nil, fmt.Errorf("block not found") - } - - blockNum := block.NumberU64() - transactions := block.Transactions() - result := make(map[common.Hash][]*types.InnerTx) - - // Retrieve inner transactions for each transaction in the block - for i, tx := range transactions { - innerTxs, err := rawdb.ReadInnerTxs(api.b.ChainDb(), blockNum, uint32(i)) - if err != nil { - continue - } - if len(innerTxs) > 0 { - // Use transaction hash as key - result[tx.Hash()] = innerTxs - } - } - - return result, nil -} diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 8b19e27405..e094bb53be 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -103,12 +103,6 @@ type Backend interface { NewMatcherBackend() filtermaps.MatcherBackend } -// For X Layer - InnerTxBackend extends Backend with inner transaction support -type XLayerBackend interface { - Backend - IsInnerTxEnabled() bool -} - func GetAPIs(apiBackend Backend) []rpc.API { nonceLock := new(AddrLocker) return []rpc.API{