mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
implemented our own bundle simulation and signedByOther
This commit is contained in:
parent
d1d9f34e51
commit
2ee9f364ab
6 changed files with 853 additions and 7 deletions
|
|
@ -117,7 +117,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||||
receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
|
receipt, _, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,20 +167,90 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
||||||
return receipt, err
|
return receipt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, *ExecutionResult, error) {
|
||||||
|
// Create a new context to be used in the EVM environment.
|
||||||
|
txContext := NewEVMTxContext(msg)
|
||||||
|
evm.Reset(txContext, statedb)
|
||||||
|
|
||||||
|
// 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 config.IsByzantium(blockNumber) {
|
||||||
|
statedb.Finalise(true)
|
||||||
|
} else {
|
||||||
|
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
|
||||||
|
}
|
||||||
|
*usedGas += result.UsedGas
|
||||||
|
|
||||||
|
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
||||||
|
// by the tx.
|
||||||
|
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
|
||||||
|
if result.Failed() {
|
||||||
|
receipt.Status = types.ReceiptStatusFailed
|
||||||
|
} else {
|
||||||
|
receipt.Status = types.ReceiptStatusSuccessful
|
||||||
|
}
|
||||||
|
receipt.TxHash = tx.Hash()
|
||||||
|
receipt.GasUsed = result.UsedGas
|
||||||
|
|
||||||
|
if tx.Type() == types.BlobTxType {
|
||||||
|
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
||||||
|
receipt.BlobGasPrice = evm.Context.BlobBaseFee
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
|
if msg.To == nil {
|
||||||
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the receipt logs and create the bloom filter.
|
||||||
|
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
||||||
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
receipt.BlockHash = blockHash
|
||||||
|
receipt.BlockNumber = blockNumber
|
||||||
|
receipt.TransactionIndex = uint(statedb.TxIndex())
|
||||||
|
return receipt, result, err
|
||||||
|
}
|
||||||
|
|
||||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment. It returns the receipt
|
// and uses the input parameters for its environment. It returns the receipt
|
||||||
// for the transaction, gas used and an error if the transaction failed,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// indicating the block was invalid.
|
||||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, *ExecutionResult, error) {
|
||||||
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new context to be used in the EVM environment
|
||||||
|
blockContext := NewEVMBlockContext(header, bc, author)
|
||||||
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
|
||||||
|
return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a modified version of ApplyTransaction that allows the sender to be
|
||||||
|
// different from the signer. This is used for the "signed by other" feature.
|
||||||
|
func ApplyTransactionSignedByOther(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, originalSender common.Address) (*types.Receipt, *ExecutionResult, error) {
|
||||||
|
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the sender to the original sender and set the nonce accordingly
|
||||||
|
msg.From = originalSender
|
||||||
|
nonce := statedb.GetNonce(originalSender)
|
||||||
|
msg.Nonce = nonce
|
||||||
|
|
||||||
// Create a new context to be used in the EVM environment
|
// Create a new context to be used in the EVM environment
|
||||||
blockContext := NewEVMBlockContext(header, bc, author)
|
blockContext := NewEVMBlockContext(header, bc, author)
|
||||||
txContext := NewEVMTxContext(msg)
|
txContext := NewEVMTxContext(msg)
|
||||||
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg)
|
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg)
|
||||||
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ func makeExtraData(extra []byte) []byte {
|
||||||
// APIs return the collection of RPC services the ethereum package offers.
|
// APIs return the collection of RPC services the ethereum package offers.
|
||||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||||
func (s *Ethereum) APIs() []rpc.API {
|
func (s *Ethereum) APIs() []rpc.API {
|
||||||
apis := ethapi.GetAPIs(s.APIBackend)
|
apis := ethapi.GetAPIs(s.APIBackend, s.blockchain)
|
||||||
|
|
||||||
// Append any APIs exposed explicitly by the consensus engine
|
// Append any APIs exposed explicitly by the consensus engine
|
||||||
apis = append(apis, s.engine.APIs(s.BlockChain())...)
|
apis = append(apis, s.engine.APIs(s.BlockChain())...)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"crypto/rand"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -51,6 +52,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
|
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
|
||||||
|
|
@ -2173,3 +2176,773 @@ func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SMG additions for ninja
|
||||||
|
// many changes are from https://github.com/0x2mev/mevexec
|
||||||
|
// MEVEXEC ADDITIONS
|
||||||
|
// the following are additional rpc methods added into the execution client for mev searchers
|
||||||
|
|
||||||
|
// BlockChainAPI provides an API to access Ethereum blockchain data.
|
||||||
|
type SearcherAPI struct {
|
||||||
|
b Backend
|
||||||
|
chain *core.BlockChain
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearcherAPI(b Backend, chain *core.BlockChain) *SearcherAPI {
|
||||||
|
return &SearcherAPI{b, chain}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallBundleArgs represents the arguments for a call.
|
||||||
|
// TODO nick evaluate and maybe get rid of CreateAccessList, StateOverrides, MixDigest
|
||||||
|
type CallBundleArgs struct {
|
||||||
|
Txs []hexutil.Bytes `json:"txs"`
|
||||||
|
BlockNumber rpc.BlockNumber `json:"blockNumber"`
|
||||||
|
StateBlockNumberOrHash rpc.BlockNumberOrHash `json:"stateBlockNumber"`
|
||||||
|
Coinbase *string `json:"coinbase"`
|
||||||
|
Timestamp *uint64 `json:"timestamp"`
|
||||||
|
Timeout *int64 `json:"timeout"`
|
||||||
|
GasLimit *uint64 `json:"gasLimit"`
|
||||||
|
Difficulty *hexutil.Big `json:"difficulty"`
|
||||||
|
BaseFee *hexutil.Big `json:"baseFee"`
|
||||||
|
SimulationLogs bool `json:"simulationLogs"`
|
||||||
|
// CreateAccessList bool `json:"createAccessList"`
|
||||||
|
StateOverrides *StateOverride `json:"stateOverrides"`
|
||||||
|
MixDigest *common.Hash `json:"mixDigest"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallBundleArgs represents the arguments for a call.
|
||||||
|
type CallBundleSignedByOther struct {
|
||||||
|
Txs []hexutil.Bytes `json:"txs"`
|
||||||
|
TxsSignedByOther []hexutil.Bytes `json:"txsSignedByOther"`
|
||||||
|
OriginalSenders []common.Address `json:"originalSenders"`
|
||||||
|
BlockNumber rpc.BlockNumber `json:"blockNumber"`
|
||||||
|
StateBlockNumberOrHash rpc.BlockNumberOrHash `json:"stateBlockNumber"`
|
||||||
|
Coinbase *string `json:"coinbase"`
|
||||||
|
Timestamp *uint64 `json:"timestamp"`
|
||||||
|
Timeout *int64 `json:"timeout"`
|
||||||
|
GasLimit *uint64 `json:"gasLimit"`
|
||||||
|
Difficulty *hexutil.Big `json:"difficulty"`
|
||||||
|
BaseFee *hexutil.Big `json:"baseFee"`
|
||||||
|
SimulationLogs bool `json:"simulationLogs"`
|
||||||
|
CreateAccessList bool `json:"createAccessList"`
|
||||||
|
StateOverrides *StateOverride `json:"stateOverrides"`
|
||||||
|
MixDigest *common.Hash `json:"mixDigest"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallBundle will simulate a bundle of transactions at the top of a given block
|
||||||
|
// number with the state of another (or the same) block. This can be used to
|
||||||
|
// simulate future blocks with the current state, or it can be used to simulate
|
||||||
|
// a past block.
|
||||||
|
// The sender is responsible for signing the transactions and using the correct
|
||||||
|
// nonce and ensuring validity
|
||||||
|
func (s *SearcherAPI) CallBundle(ctx context.Context, args CallBundleArgs) (map[string]interface{}, error) {
|
||||||
|
if len(args.Txs) == 0 {
|
||||||
|
return nil, errors.New("bundle missing txs")
|
||||||
|
}
|
||||||
|
if args.BlockNumber == 0 {
|
||||||
|
return nil, errors.New("bundle missing blockNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
var txs types.Transactions
|
||||||
|
|
||||||
|
for _, encodedTx := range args.Txs {
|
||||||
|
tx := new(types.Transaction)
|
||||||
|
if err := tx.UnmarshalBinary(encodedTx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debug("Decoded tx", "tx", tx)
|
||||||
|
txs = append(txs, tx)
|
||||||
|
}
|
||||||
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||||
|
|
||||||
|
timeoutMilliSeconds := int64(5000)
|
||||||
|
if args.Timeout != nil {
|
||||||
|
timeoutMilliSeconds = *args.Timeout
|
||||||
|
}
|
||||||
|
timeout := time.Millisecond * time.Duration(timeoutMilliSeconds)
|
||||||
|
state, parent, err := s.b.StateAndHeaderByNumberOrHash(ctx, args.StateBlockNumberOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := args.StateOverrides.Apply(state); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockNumber := big.NewInt(int64(args.BlockNumber))
|
||||||
|
|
||||||
|
timestamp := parent.Time + 1
|
||||||
|
if args.Timestamp != nil {
|
||||||
|
timestamp = *args.Timestamp
|
||||||
|
}
|
||||||
|
coinbase := parent.Coinbase
|
||||||
|
if args.Coinbase != nil {
|
||||||
|
coinbase = common.HexToAddress(*args.Coinbase)
|
||||||
|
}
|
||||||
|
difficulty := parent.Difficulty
|
||||||
|
if args.Difficulty != nil {
|
||||||
|
difficulty = args.Difficulty.ToInt()
|
||||||
|
}
|
||||||
|
gasLimit := parent.GasLimit
|
||||||
|
if args.GasLimit != nil {
|
||||||
|
gasLimit = *args.GasLimit
|
||||||
|
}
|
||||||
|
var baseFee *big.Int
|
||||||
|
if args.BaseFee != nil {
|
||||||
|
baseFee = args.BaseFee.ToInt()
|
||||||
|
} else if s.b.ChainConfig().IsLondon(big.NewInt(args.BlockNumber.Int64())) {
|
||||||
|
baseFee = eip1559.CalcBaseFee(s.b.ChainConfig(), parent)
|
||||||
|
}
|
||||||
|
header := &types.Header{
|
||||||
|
ParentHash: parent.Hash(),
|
||||||
|
Number: blockNumber,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
Time: timestamp,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
Coinbase: coinbase,
|
||||||
|
BaseFee: baseFee,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup context so it may be cancelled the call has completed
|
||||||
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
if timeout > 0 {
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||||
|
} else {
|
||||||
|
ctx, cancel = context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
// Make sure the context is cancelled when the call has completed
|
||||||
|
// this makes sure resources are cleaned up.
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
vmconfig := vm.Config{}
|
||||||
|
|
||||||
|
// Setup the gas pool (also for unmetered requests)
|
||||||
|
// and apply the message.
|
||||||
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
|
results := []map[string]interface{}{}
|
||||||
|
coinbaseBalanceBefore := state.GetBalance(coinbase)
|
||||||
|
|
||||||
|
bundleHash := sha3.NewLegacyKeccak256()
|
||||||
|
signer := types.MakeSigner(s.b.ChainConfig(), blockNumber, header.Time)
|
||||||
|
var totalGasUsed uint64
|
||||||
|
gasFees := new(big.Int)
|
||||||
|
for i, tx := range txs {
|
||||||
|
coinbaseBalanceBeforeTx := state.GetBalance(coinbase)
|
||||||
|
state.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
|
// for now i do not want to use the access list stuff
|
||||||
|
// accessListState := state.Copy() // create a copy just in case we use it later for access list creation
|
||||||
|
|
||||||
|
receipt, result, err := core.ApplyTransaction(s.b.ChainConfig(), s.chain, &coinbase, gp, state, header, tx, &header.GasUsed, vmconfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash := tx.Hash().String()
|
||||||
|
from, err := types.Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
to := "0x"
|
||||||
|
if tx.To() != nil {
|
||||||
|
to = tx.To().String()
|
||||||
|
}
|
||||||
|
jsonResult := map[string]interface{}{
|
||||||
|
"txHash": txHash,
|
||||||
|
"gasUsed": receipt.GasUsed,
|
||||||
|
"fromAddress": from.String(),
|
||||||
|
"toAddress": to,
|
||||||
|
}
|
||||||
|
totalGasUsed += receipt.GasUsed
|
||||||
|
gasPrice, err := tx.EffectiveGasTip(header.BaseFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
gasFeesTx := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), gasPrice)
|
||||||
|
gasFees.Add(gasFees, gasFeesTx)
|
||||||
|
bundleHash.Write(tx.Hash().Bytes())
|
||||||
|
if result.Err != nil {
|
||||||
|
jsonResult["error"] = result.Err.Error()
|
||||||
|
revert := result.Revert()
|
||||||
|
if len(revert) > 0 {
|
||||||
|
jsonResult["revert"] = string(revert)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dst := make([]byte, hex.EncodedLen(len(result.Return())))
|
||||||
|
hex.Encode(dst, result.Return())
|
||||||
|
jsonResult["value"] = "0x" + string(dst)
|
||||||
|
}
|
||||||
|
// if simulation logs are requested append it to logs
|
||||||
|
if args.SimulationLogs {
|
||||||
|
jsonResult["logs"] = receipt.Logs
|
||||||
|
}
|
||||||
|
// i want to cut all that access list stuff. i do not think i need it
|
||||||
|
// // if an access list is requested create and append
|
||||||
|
// if args.CreateAccessList {
|
||||||
|
// // ifdk another way to fill all values so this will have to do - x2
|
||||||
|
// txArgGas := hexutil.Uint64(tx.Gas())
|
||||||
|
// txArgNonce := hexutil.Uint64(tx.Nonce())
|
||||||
|
// txArgData := hexutil.Bytes(tx.Data())
|
||||||
|
// txargs := TransactionArgs{
|
||||||
|
// From: &from,
|
||||||
|
// To: tx.To(),
|
||||||
|
// Gas: &txArgGas,
|
||||||
|
// Nonce: &txArgNonce,
|
||||||
|
// Data: &txArgData,
|
||||||
|
// Value: (*hexutil.Big)(tx.Value()),
|
||||||
|
// ChainID: (*hexutil.Big)(tx.ChainId()),
|
||||||
|
// }
|
||||||
|
// if tx.GasFeeCap().Cmp(big.NewInt(0)) == 0 { // no maxbasefee, set gasprice instead
|
||||||
|
// txargs.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
||||||
|
// } else { // otherwise set base and priority fee
|
||||||
|
// txargs.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
// txargs.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
// }
|
||||||
|
// acl, gasUsed, vmerr, err := AccessListOnState(ctx, s.b, header, accessListState, txargs)
|
||||||
|
// if err == nil {
|
||||||
|
// if gasUsed != receipt.GasUsed {
|
||||||
|
// log.Debug("Gas used in receipt differ from accesslist", "receipt", receipt.GasUsed, "acl", gasUsed) // weird bug but it works
|
||||||
|
// }
|
||||||
|
// if vmerr != nil {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered vmerr", "vmerr", vmerr)
|
||||||
|
// }
|
||||||
|
// jsonResult["accessList"] = acl
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered err", "err", err)
|
||||||
|
// jsonResult["accessList"] = acl //
|
||||||
|
// } // return the empty accesslist either way
|
||||||
|
// }
|
||||||
|
coinbaseDiffTx := new(uint256.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBeforeTx)
|
||||||
|
jsonResult["coinbaseDiff"] = coinbaseDiffTx.String()
|
||||||
|
jsonResult["gasFees"] = gasFeesTx.String()
|
||||||
|
jsonResult["ethSentToCoinbase"] = new(uint256.Int).Sub(coinbaseDiffTx, uint256.MustFromBig(gasFeesTx)).String()
|
||||||
|
jsonResult["gasPrice"] = new(uint256.Int).Div(coinbaseDiffTx, uint256.NewInt(receipt.GasUsed)).String()
|
||||||
|
jsonResult["gasUsed"] = receipt.GasUsed
|
||||||
|
results = append(results, jsonResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := map[string]interface{}{}
|
||||||
|
ret["results"] = results
|
||||||
|
coinbaseDiff := new(uint256.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBefore)
|
||||||
|
ret["coinbaseDiff"] = coinbaseDiff.String()
|
||||||
|
ret["gasFees"] = gasFees.String()
|
||||||
|
ret["ethSentToCoinbase"] = new(uint256.Int).Sub(coinbaseDiff, uint256.MustFromBig(gasFees)).String()
|
||||||
|
ret["bundleGasPrice"] = new(uint256.Int).Div(coinbaseDiff, uint256.NewInt(totalGasUsed)).String()
|
||||||
|
ret["totalGasUsed"] = totalGasUsed
|
||||||
|
ret["stateBlockNumber"] = parent.Number.Int64()
|
||||||
|
|
||||||
|
ret["bundleHash"] = "0x" + common.Bytes2Hex(bundleHash.Sum(nil))
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a modified version of the function CallBundle
|
||||||
|
// It is modified to allow for transactions to be signed by different addresses than the one that is sending it.
|
||||||
|
func (s *SearcherAPI) CallBundleSignedByOther(ctx context.Context, args CallBundleSignedByOther) (map[string]interface{}, error) {
|
||||||
|
// if len(args.Txs) == 0 {
|
||||||
|
// return nil, errors.New("bundle missing txs")
|
||||||
|
// }
|
||||||
|
if args.BlockNumber == 0 {
|
||||||
|
return nil, errors.New("bundle missing blockNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
var txsSignedByOther types.Transactions
|
||||||
|
var txs types.Transactions
|
||||||
|
|
||||||
|
for _, encodedTx := range args.TxsSignedByOther {
|
||||||
|
tx := new(types.Transaction)
|
||||||
|
if err := tx.UnmarshalBinary(encodedTx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
txsSignedByOther = append(txsSignedByOther, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, encodedTx := range args.Txs {
|
||||||
|
tx := new(types.Transaction)
|
||||||
|
if err := tx.UnmarshalBinary(encodedTx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
txs = append(txs, tx)
|
||||||
|
}
|
||||||
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||||
|
|
||||||
|
timeoutMilliSeconds := int64(5000)
|
||||||
|
if args.Timeout != nil {
|
||||||
|
timeoutMilliSeconds = *args.Timeout
|
||||||
|
}
|
||||||
|
timeout := time.Millisecond * time.Duration(timeoutMilliSeconds)
|
||||||
|
state, parent, err := s.b.StateAndHeaderByNumberOrHash(ctx, args.StateBlockNumberOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := args.StateOverrides.Apply(state); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockNumber := big.NewInt(int64(args.BlockNumber))
|
||||||
|
|
||||||
|
timestamp := parent.Time + 12
|
||||||
|
if args.Timestamp != nil {
|
||||||
|
timestamp = *args.Timestamp
|
||||||
|
}
|
||||||
|
coinbase := parent.Coinbase
|
||||||
|
if args.Coinbase != nil {
|
||||||
|
coinbase = common.HexToAddress(*args.Coinbase)
|
||||||
|
}
|
||||||
|
difficulty := parent.Difficulty
|
||||||
|
if args.Difficulty != nil {
|
||||||
|
difficulty = args.Difficulty.ToInt()
|
||||||
|
}
|
||||||
|
gasLimit := parent.GasLimit
|
||||||
|
if args.GasLimit != nil {
|
||||||
|
gasLimit = *args.GasLimit
|
||||||
|
}
|
||||||
|
var baseFee *big.Int
|
||||||
|
if args.BaseFee != nil {
|
||||||
|
baseFee = args.BaseFee.ToInt()
|
||||||
|
} else if s.b.ChainConfig().IsLondon(big.NewInt(args.BlockNumber.Int64())) {
|
||||||
|
baseFee = eip1559.CalcBaseFee(s.b.ChainConfig(), parent)
|
||||||
|
}
|
||||||
|
mixDigest := parent.MixDigest
|
||||||
|
if args.MixDigest != nil {
|
||||||
|
mixDigest = *args.MixDigest
|
||||||
|
}
|
||||||
|
header := &types.Header{
|
||||||
|
ParentHash: parent.Hash(),
|
||||||
|
Number: blockNumber,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
Time: timestamp,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
Coinbase: coinbase,
|
||||||
|
BaseFee: baseFee,
|
||||||
|
MixDigest: mixDigest,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup context so it may be cancelled the call has completed
|
||||||
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
if timeout > 0 {
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||||
|
} else {
|
||||||
|
ctx, cancel = context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
// Make sure the context is cancelled when the call has completed
|
||||||
|
// this makes sure resources are cleaned up.
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
vmconfig := vm.Config{}
|
||||||
|
|
||||||
|
// Setup the gas pool (also for unmetered requests)
|
||||||
|
// and apply the message.
|
||||||
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
|
results := []map[string]interface{}{}
|
||||||
|
coinbaseBalanceBefore := state.GetBalance(coinbase)
|
||||||
|
|
||||||
|
bundleHash := sha3.NewLegacyKeccak256()
|
||||||
|
signer := types.MakeSigner(s.b.ChainConfig(), header.Number, header.Time)
|
||||||
|
var totalGasUsed uint64
|
||||||
|
gasFees := new(big.Int)
|
||||||
|
|
||||||
|
for i, tx := range txsSignedByOther {
|
||||||
|
coinbaseBalanceBeforeTx := state.GetBalance(coinbase)
|
||||||
|
state.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
|
// accessListState := state.Copy() // create a copy just in case we use it later for access list creation
|
||||||
|
receipt, result, err := core.ApplyTransactionSignedByOther(s.b.ChainConfig(), s.chain, &coinbase, gp, state, header, tx, &header.GasUsed, vmconfig, args.OriginalSenders[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash := tx.Hash().String()
|
||||||
|
from, err := types.Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
to := "0x"
|
||||||
|
if tx.To() != nil {
|
||||||
|
to = tx.To().String()
|
||||||
|
}
|
||||||
|
jsonResult := map[string]interface{}{
|
||||||
|
"txHash": txHash,
|
||||||
|
"gasUsed": receipt.GasUsed,
|
||||||
|
"fromAddress": from.String(),
|
||||||
|
"toAddress": to,
|
||||||
|
}
|
||||||
|
totalGasUsed += receipt.GasUsed
|
||||||
|
gasPrice, err := tx.EffectiveGasTip(header.BaseFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
gasFeesTx := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), gasPrice)
|
||||||
|
gasFees.Add(gasFees, gasFeesTx)
|
||||||
|
bundleHash.Write(tx.Hash().Bytes())
|
||||||
|
if result.Err != nil {
|
||||||
|
jsonResult["error"] = result.Err.Error()
|
||||||
|
revert := result.Revert()
|
||||||
|
if len(revert) > 0 {
|
||||||
|
jsonResult["revert"] = string(revert)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dst := make([]byte, hex.EncodedLen(len(result.Return())))
|
||||||
|
hex.Encode(dst, result.Return())
|
||||||
|
jsonResult["value"] = "0x" + string(dst)
|
||||||
|
}
|
||||||
|
// if simulation logs are requested append it to logs
|
||||||
|
if args.SimulationLogs {
|
||||||
|
jsonResult["logs"] = receipt.Logs
|
||||||
|
}
|
||||||
|
// // if an access list is requested create and append
|
||||||
|
// if args.CreateAccessList {
|
||||||
|
// // ifdk another way to fill all values so this will have to do - x2
|
||||||
|
// txArgGas := hexutil.Uint64(tx.Gas())
|
||||||
|
// txArgNonce := hexutil.Uint64(tx.Nonce())
|
||||||
|
// txArgData := hexutil.Bytes(tx.Data())
|
||||||
|
// txargs := TransactionArgs{
|
||||||
|
// From: &from,
|
||||||
|
// To: tx.To(),
|
||||||
|
// Gas: &txArgGas,
|
||||||
|
// Nonce: &txArgNonce,
|
||||||
|
// Data: &txArgData,
|
||||||
|
// Value: (*hexutil.Big)(tx.Value()),
|
||||||
|
// ChainID: (*hexutil.Big)(tx.ChainId()),
|
||||||
|
// }
|
||||||
|
// if tx.GasFeeCap().Cmp(big.NewInt(0)) == 0 { // no maxbasefee, set gasprice instead
|
||||||
|
// txargs.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
||||||
|
// } else { // otherwise set base and priority fee
|
||||||
|
// txargs.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
// txargs.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
// }
|
||||||
|
// acl, gasUsed, vmerr, err := AccessListOnState(ctx, s.b, header, accessListState, txargs)
|
||||||
|
// if err == nil {
|
||||||
|
// if gasUsed != receipt.GasUsed {
|
||||||
|
// log.Debug("Gas used in receipt differ from accesslist", "receipt", receipt.GasUsed, "acl", gasUsed) // weird bug but it works
|
||||||
|
// }
|
||||||
|
// if vmerr != nil {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered vmerr", "vmerr", vmerr)
|
||||||
|
// }
|
||||||
|
// jsonResult["accessList"] = acl
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered err", "err", err)
|
||||||
|
// jsonResult["accessList"] = acl //
|
||||||
|
// } // return the empty accesslist either way
|
||||||
|
// }
|
||||||
|
coinbaseDiffTx := new(uint256.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBeforeTx)
|
||||||
|
jsonResult["coinbaseDiff"] = coinbaseDiffTx.String()
|
||||||
|
jsonResult["gasFees"] = gasFeesTx.String()
|
||||||
|
jsonResult["ethSentToCoinbase"] = new(uint256.Int).Sub(coinbaseDiffTx, uint256.MustFromBig(gasFeesTx)).String()
|
||||||
|
jsonResult["gasPrice"] = new(uint256.Int).Div(coinbaseDiffTx, uint256.NewInt(receipt.GasUsed)).String()
|
||||||
|
jsonResult["gasUsed"] = receipt.GasUsed
|
||||||
|
results = append(results, jsonResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tx := range txs {
|
||||||
|
coinbaseBalanceBeforeTx := state.GetBalance(coinbase)
|
||||||
|
state.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
|
// accessListState := state.Copy() // create a copy just in case we use it later for access list creation
|
||||||
|
|
||||||
|
receipt, result, err := core.ApplyTransaction(s.b.ChainConfig(), s.chain, &coinbase, gp, state, header, tx, &header.GasUsed, vmconfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash := tx.Hash().String()
|
||||||
|
from, err := types.Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
to := "0x"
|
||||||
|
if tx.To() != nil {
|
||||||
|
to = tx.To().String()
|
||||||
|
}
|
||||||
|
jsonResult := map[string]interface{}{
|
||||||
|
"txHash": txHash,
|
||||||
|
"gasUsed": receipt.GasUsed,
|
||||||
|
"fromAddress": from.String(),
|
||||||
|
"toAddress": to,
|
||||||
|
}
|
||||||
|
totalGasUsed += receipt.GasUsed
|
||||||
|
gasPrice, err := tx.EffectiveGasTip(header.BaseFee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
|
||||||
|
}
|
||||||
|
gasFeesTx := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), gasPrice)
|
||||||
|
gasFees.Add(gasFees, gasFeesTx)
|
||||||
|
bundleHash.Write(tx.Hash().Bytes())
|
||||||
|
if result.Err != nil {
|
||||||
|
jsonResult["error"] = result.Err.Error()
|
||||||
|
revert := result.Revert()
|
||||||
|
if len(revert) > 0 {
|
||||||
|
jsonResult["revert"] = string(revert)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dst := make([]byte, hex.EncodedLen(len(result.Return())))
|
||||||
|
hex.Encode(dst, result.Return())
|
||||||
|
jsonResult["value"] = "0x" + string(dst)
|
||||||
|
}
|
||||||
|
// if simulation logs are requested append it to logs
|
||||||
|
if args.SimulationLogs {
|
||||||
|
jsonResult["logs"] = receipt.Logs
|
||||||
|
}
|
||||||
|
// // if an access list is requested create and append
|
||||||
|
// if args.CreateAccessList {
|
||||||
|
// // ifdk another way to fill all values so this will have to do - x2
|
||||||
|
// txArgGas := hexutil.Uint64(tx.Gas())
|
||||||
|
// txArgNonce := hexutil.Uint64(tx.Nonce())
|
||||||
|
// txArgData := hexutil.Bytes(tx.Data())
|
||||||
|
// txargs := TransactionArgs{
|
||||||
|
// From: &from,
|
||||||
|
// To: tx.To(),
|
||||||
|
// Gas: &txArgGas,
|
||||||
|
// Nonce: &txArgNonce,
|
||||||
|
// Data: &txArgData,
|
||||||
|
// Value: (*hexutil.Big)(tx.Value()),
|
||||||
|
// ChainID: (*hexutil.Big)(tx.ChainId()),
|
||||||
|
// }
|
||||||
|
// if tx.GasFeeCap().Cmp(big.NewInt(0)) == 0 { // no maxbasefee, set gasprice instead
|
||||||
|
// txargs.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
||||||
|
// } else { // otherwise set base and priority fee
|
||||||
|
// txargs.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
// txargs.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
// }
|
||||||
|
// acl, gasUsed, vmerr, err := AccessListOnState(ctx, s.b, header, accessListState, txargs)
|
||||||
|
// if err == nil {
|
||||||
|
// if gasUsed != receipt.GasUsed {
|
||||||
|
// log.Debug("Gas used in receipt differ from accesslist", "receipt", receipt.GasUsed, "acl", gasUsed) // weird bug but it works
|
||||||
|
// }
|
||||||
|
// if vmerr != nil {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered vmerr", "vmerr", vmerr)
|
||||||
|
// }
|
||||||
|
// jsonResult["accessList"] = acl
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered err", "err", err)
|
||||||
|
// jsonResult["accessList"] = acl //
|
||||||
|
// } // return the empty accesslist either way
|
||||||
|
// }
|
||||||
|
coinbaseDiffTx := new(uint256.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBeforeTx)
|
||||||
|
jsonResult["coinbaseDiff"] = coinbaseDiffTx.String()
|
||||||
|
jsonResult["gasFees"] = gasFeesTx.String()
|
||||||
|
jsonResult["ethSentToCoinbase"] = new(uint256.Int).Sub(coinbaseDiffTx, uint256.MustFromBig(gasFeesTx)).String()
|
||||||
|
jsonResult["gasPrice"] = new(uint256.Int).Div(coinbaseDiffTx, uint256.NewInt(receipt.GasUsed)).String()
|
||||||
|
jsonResult["gasUsed"] = receipt.GasUsed
|
||||||
|
results = append(results, jsonResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := map[string]interface{}{}
|
||||||
|
ret["results"] = results
|
||||||
|
coinbaseDiff := new(uint256.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBefore)
|
||||||
|
ret["coinbaseDiff"] = coinbaseDiff.String()
|
||||||
|
ret["gasFees"] = gasFees.String()
|
||||||
|
ret["ethSentToCoinbase"] = new(uint256.Int).Sub(coinbaseDiff, uint256.MustFromBig(gasFees)).String()
|
||||||
|
ret["bundleGasPrice"] = new(uint256.Int).Div(coinbaseDiff, uint256.NewInt(totalGasUsed)).String()
|
||||||
|
ret["totalGasUsed"] = totalGasUsed
|
||||||
|
ret["stateBlockNumber"] = parent.Number.Int64()
|
||||||
|
|
||||||
|
ret["bundleHash"] = "0x" + common.Bytes2Hex(bundleHash.Sum(nil))
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateGasBundleArgs are possible args for eth_estimateGasBundle
|
||||||
|
type EstimateGasBundleArgs struct {
|
||||||
|
Txs []TransactionArgs `json:"txs"`
|
||||||
|
BlockNumber rpc.BlockNumber `json:"blockNumber"`
|
||||||
|
StateBlockNumberOrHash rpc.BlockNumberOrHash `json:"stateBlockNumber"`
|
||||||
|
Coinbase *string `json:"coinbase"`
|
||||||
|
Timestamp *uint64 `json:"timestamp"`
|
||||||
|
Timeout *int64 `json:"timeout"`
|
||||||
|
StateOverrides *StateOverride `json:"stateOverrides"`
|
||||||
|
CreateAccessList bool `json:"createAccessList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbundle, but doesnt require signing
|
||||||
|
func (s *SearcherAPI) EstimateGasBundle(ctx context.Context, args EstimateGasBundleArgs) (map[string]interface{}, error) {
|
||||||
|
if len(args.Txs) == 0 {
|
||||||
|
return nil, errors.New("bundle missing txs")
|
||||||
|
}
|
||||||
|
if args.BlockNumber == 0 {
|
||||||
|
return nil, errors.New("bundle missing blockNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutMS := int64(5000)
|
||||||
|
if args.Timeout != nil {
|
||||||
|
timeoutMS = *args.Timeout
|
||||||
|
}
|
||||||
|
timeout := time.Millisecond * time.Duration(timeoutMS)
|
||||||
|
|
||||||
|
state, parent, err := s.b.StateAndHeaderByNumberOrHash(ctx, args.StateBlockNumberOrHash)
|
||||||
|
if state == nil || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := args.StateOverrides.Apply(state); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blockNumber := big.NewInt(int64(args.BlockNumber))
|
||||||
|
timestamp := parent.Time + 1
|
||||||
|
if args.Timestamp != nil {
|
||||||
|
timestamp = *args.Timestamp
|
||||||
|
}
|
||||||
|
coinbase := parent.Coinbase
|
||||||
|
if args.Coinbase != nil {
|
||||||
|
coinbase = common.HexToAddress(*args.Coinbase)
|
||||||
|
}
|
||||||
|
|
||||||
|
header := &types.Header{
|
||||||
|
ParentHash: parent.Hash(),
|
||||||
|
Number: blockNumber,
|
||||||
|
GasLimit: parent.GasLimit,
|
||||||
|
Time: timestamp,
|
||||||
|
Difficulty: parent.Difficulty,
|
||||||
|
Coinbase: coinbase,
|
||||||
|
BaseFee: parent.BaseFee,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup context so it may be cancelled when the call
|
||||||
|
// has completed or, in case of unmetered gas, setup
|
||||||
|
// a context with a timeout
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
if timeout > 0 {
|
||||||
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||||
|
} else {
|
||||||
|
ctx, cancel = context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the context is cancelled when the call has completed
|
||||||
|
// This makes sure resources are cleaned up
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Results
|
||||||
|
results := []map[string]interface{}{}
|
||||||
|
|
||||||
|
// Copy the original db so we don't modify it
|
||||||
|
statedb := state.Copy()
|
||||||
|
|
||||||
|
// Gas pool
|
||||||
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
|
// Block context
|
||||||
|
blockContext := core.NewEVMBlockContext(header, s.chain, &coinbase)
|
||||||
|
|
||||||
|
// Feed each of the transactions into the VM ctx
|
||||||
|
// And try and estimate the gas used
|
||||||
|
for i, txArgs := range args.Txs {
|
||||||
|
// Since its a txCall we'll just prepare the
|
||||||
|
// state with a random hash
|
||||||
|
var randomHash common.Hash
|
||||||
|
rand.Read(randomHash[:])
|
||||||
|
|
||||||
|
// New random hash since its a call
|
||||||
|
statedb.SetTxContext(randomHash, i)
|
||||||
|
|
||||||
|
// accessListState := statedb.Copy() // create a copy just in case we use it later for access list creation
|
||||||
|
|
||||||
|
// Convert tx args to msg to apply state transition
|
||||||
|
msg := txArgs.ToMessage(header.BaseFee)
|
||||||
|
|
||||||
|
// Prepare the hashes
|
||||||
|
txContext := core.NewEVMTxContext(msg)
|
||||||
|
|
||||||
|
// Get EVM Environment
|
||||||
|
vmenv := vm.NewEVM(blockContext, txContext, statedb, s.b.ChainConfig(), vm.Config{NoBaseFee: true})
|
||||||
|
|
||||||
|
// Apply state transition
|
||||||
|
result, err := core.ApplyMessage(vmenv, msg, gp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifications are committed to the state
|
||||||
|
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||||
|
statedb.Finalise(vmenv.ChainConfig().IsEIP158(blockNumber))
|
||||||
|
|
||||||
|
// Append result
|
||||||
|
jsonResult := map[string]interface{}{
|
||||||
|
"gasUsed": result.UsedGas,
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Err != nil {
|
||||||
|
jsonResult["error"] = result.Err.Error()
|
||||||
|
revert := result.Revert()
|
||||||
|
if len(revert) > 0 {
|
||||||
|
jsonResult["revert"] = string(revert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result.ReturnData) > 0 {
|
||||||
|
jsonResult["data"] = hexutil.Bytes(result.ReturnData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO nick - why are no logs being returned? - we never use this anyways. callBundle already returns gas costs
|
||||||
|
// if simulation logs are requested append it to logs
|
||||||
|
|
||||||
|
// // if an access list is requested create and append
|
||||||
|
// if args.CreateAccessList {
|
||||||
|
// // welp guess we're copying these again sigh
|
||||||
|
// txArgFrom := msg.From
|
||||||
|
// txArgGas := hexutil.Uint64(msg.GasLimit)
|
||||||
|
// txArgNonce := hexutil.Uint64(msg.Nonce)
|
||||||
|
// txArgData := hexutil.Bytes(msg.Data)
|
||||||
|
// txargs := TransactionArgs{
|
||||||
|
// From: &txArgFrom,
|
||||||
|
// To: msg.To,
|
||||||
|
// Gas: &txArgGas,
|
||||||
|
// Nonce: &txArgNonce,
|
||||||
|
// Data: &txArgData,
|
||||||
|
// ChainID: (*hexutil.Big)(s.chain.Config().ChainID),
|
||||||
|
// Value: (*hexutil.Big)(msg.Value),
|
||||||
|
// }
|
||||||
|
// if msg.GasFeeCap.Cmp(big.NewInt(0)) == 0 { // no maxbasefee, set gasprice instead
|
||||||
|
// txargs.GasPrice = (*hexutil.Big)(msg.GasPrice)
|
||||||
|
// } else { // otherwise set base and priority fee
|
||||||
|
// txargs.MaxFeePerGas = (*hexutil.Big)(msg.GasFeeCap)
|
||||||
|
// txargs.MaxPriorityFeePerGas = (*hexutil.Big)(msg.GasTipCap)
|
||||||
|
// }
|
||||||
|
// acl, _, vmerr, err := AccessListOnState(ctx, s.b, header, accessListState, txargs)
|
||||||
|
// if err == nil {
|
||||||
|
// if vmerr != nil {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered vmerr", "vmerr", vmerr)
|
||||||
|
// }
|
||||||
|
// jsonResult["accessList"] = acl
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// log.Info("CallBundle accesslist creation encountered err", "err", err)
|
||||||
|
// jsonResult["accessList"] = acl //
|
||||||
|
// } // return the empty accesslist either way
|
||||||
|
// }
|
||||||
|
|
||||||
|
results = append(results, jsonResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return results
|
||||||
|
ret := map[string]interface{}{}
|
||||||
|
ret["results"] = results
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// // rpcMarshalCompact uses the generalized output filler, then adds the total difficulty field, which requires
|
||||||
|
// // a `PublicBlockchainAPI`.
|
||||||
|
// func (s *SearcherAPI) rpcMarshalCompactHeader(ctx context.Context, h *types.Header) map[string]interface{} {
|
||||||
|
// return RPCMarshalCompactHeader(h)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // GetCompactBlocks gets the compact block data for the given block's hash or number
|
||||||
|
// // the logs in the block can also be requested
|
||||||
|
// func (s *SearcherAPI) GetCompactBlocks(ctx context.Context, blockNrOrHashes []rpc.BlockNumberOrHash, returnLogs bool) ([]map[string]interface{}, error) {
|
||||||
|
// resultArray := make([]map[string]interface{}, 0, len(blockNrOrHashes))
|
||||||
|
// for _, blockNrOrHash := range blockNrOrHashes {
|
||||||
|
// header, err := s.b.HeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// result := s.rpcMarshalCompactHeader(ctx, header)
|
||||||
|
// if returnLogs { // add logs if requested
|
||||||
|
// logs := s.chain.GetLogsWithHeader(header)
|
||||||
|
// result["logs"] = RPCMarshalCompactLogs(logs)
|
||||||
|
// }
|
||||||
|
// resultArray = append(resultArray, result)
|
||||||
|
// }
|
||||||
|
// return resultArray, nil
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ type Backend interface {
|
||||||
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
|
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAPIs(apiBackend Backend) []rpc.API {
|
func GetAPIs(apiBackend Backend, chain *core.BlockChain) []rpc.API {
|
||||||
nonceLock := new(AddrLocker)
|
nonceLock := new(AddrLocker)
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
{
|
{
|
||||||
|
|
@ -111,6 +111,9 @@ func GetAPIs(apiBackend Backend) []rpc.API {
|
||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
Service: NewTransactionAPI(apiBackend, nonceLock),
|
Service: NewTransactionAPI(apiBackend, nonceLock),
|
||||||
|
}, {
|
||||||
|
Namespace: "eth",
|
||||||
|
Service: NewSearcherAPI(apiBackend, chain),
|
||||||
}, {
|
}, {
|
||||||
Namespace: "txpool",
|
Namespace: "txpool",
|
||||||
Service: NewTxPoolAPI(apiBackend),
|
Service: NewTxPoolAPI(apiBackend),
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
snap = env.state.Snapshot()
|
snap = env.state.Snapshot()
|
||||||
gp = env.gasPool.Gas()
|
gp = env.gasPool.Gas()
|
||||||
)
|
)
|
||||||
receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{})
|
receipt, _, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
env.gasPool.SetGas(gp)
|
env.gasPool.SetGas(gp)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue