mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
139 lines
4.7 KiB
Go
139 lines
4.7 KiB
Go
// (c) 2020-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package ethapi
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/evm/core"
|
|
"github.com/luxfi/geth/params"
|
|
"github.com/luxfi/geth/rpc"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/geth/common/hexutil"
|
|
"github.com/luxfi/geth/rlp"
|
|
)
|
|
|
|
// GetChainConfig returns the chain config.
|
|
func (api *BlockChainAPI) GetChainConfig(ctx context.Context) *params.ChainConfig {
|
|
return api.b.ChainConfig().ToEthChainConfig()
|
|
}
|
|
|
|
type DetailedExecutionResult struct {
|
|
UsedGas uint64 `json:"gas"` // Total used gas but include the refunded gas
|
|
ErrCode int `json:"errCode"` // EVM error code
|
|
Err string `json:"err"` // Any error encountered during the execution(listed in core/vm/errors.go)
|
|
ReturnData hexutil.Bytes `json:"returnData"` // Data from evm(function result or data supplied with revert opcode)
|
|
}
|
|
|
|
// CallDetailed performs the same call as Call, but returns the full context
|
|
func (s *BlockChainAPI) CallDetailed(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (*DetailedExecutionResult, error) {
|
|
result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, nil, s.b.RPCEVMTimeout(), s.b.RPCGasCap())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
reply := &DetailedExecutionResult{
|
|
UsedGas: result.UsedGas,
|
|
ReturnData: result.ReturnData,
|
|
}
|
|
if result.Err != nil {
|
|
if err, ok := result.Err.(rpc.Error); ok {
|
|
reply.ErrCode = err.ErrorCode()
|
|
}
|
|
reply.Err = result.Err.Error()
|
|
}
|
|
// If the result contains a revert reason, try to unpack and return it.
|
|
if len(result.Revert()) > 0 {
|
|
err := newRevertError(result.Revert())
|
|
reply.ErrCode = err.ErrorCode()
|
|
reply.Err = err.Error()
|
|
}
|
|
return reply, nil
|
|
}
|
|
|
|
// Note: this API is moved directly from ./eth/api.go to ensure that it is available under an API that is enabled by
|
|
// default without duplicating the code and serving the same API in the original location as well without creating a
|
|
// cyclic import.
|
|
//
|
|
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
|
|
type BadBlockArgs struct {
|
|
Hash common.Hash `json:"hash"`
|
|
Block map[string]interface{} `json:"block"`
|
|
RLP string `json:"rlp"`
|
|
Reason *core.BadBlockReason `json:"reason"`
|
|
}
|
|
|
|
// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
|
// and returns them as a JSON list of block hashes.
|
|
func (s *BlockChainAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
|
|
var (
|
|
badBlocks, reasons = s.b.BadBlocks()
|
|
results = make([]*BadBlockArgs, 0, len(badBlocks))
|
|
)
|
|
for i, block := range badBlocks {
|
|
var (
|
|
blockRlp string
|
|
blockJSON map[string]interface{}
|
|
)
|
|
if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
|
|
blockRlp = err.Error() // Hacky, but hey, it works
|
|
} else {
|
|
blockRlp = fmt.Sprintf("%#x", rlpBytes)
|
|
}
|
|
blockJSON = RPCMarshalBlock(block, true, true, s.b.ChainConfig())
|
|
results = append(results, &BadBlockArgs{
|
|
Hash: block.Hash(),
|
|
RLP: blockRlp,
|
|
Block: blockJSON,
|
|
Reason: reasons[i],
|
|
})
|
|
}
|
|
return results, nil
|
|
}
|
|
|
|
// stateQueryBlockNumberAllowed returns a nil error if:
|
|
// - the node is configured to accept any state query (the query window is zero)
|
|
// - the block given has its number within the query window before the last accepted block.
|
|
// This query window is set to [core.TipBufferSize] when running in a non-archive mode.
|
|
//
|
|
// Otherwise, it returns a non-nil error containing block number information.
|
|
func (s *BlockChainAPI) stateQueryBlockNumberAllowed(blockNumOrHash rpc.BlockNumberOrHash) (err error) {
|
|
queryWindow := uint64(core.TipBufferSize)
|
|
if s.b.IsArchive() {
|
|
queryWindow = s.b.HistoricalProofQueryWindow()
|
|
if queryWindow == 0 {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
lastAcceptedNumber := s.b.LastAcceptedBlock().NumberU64()
|
|
|
|
var number uint64
|
|
if blockNumOrHash.BlockNumber != nil {
|
|
number = uint64(blockNumOrHash.BlockNumber.Int64())
|
|
} else if blockHash, ok := blockNumOrHash.Hash(); ok {
|
|
block, err := s.b.BlockByHash(context.Background(), blockHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get block from hash: %s", err)
|
|
} else if block == nil {
|
|
return fmt.Errorf("block from hash %s doesn't exist", blockHash)
|
|
}
|
|
number = block.NumberU64()
|
|
} else {
|
|
return errors.New("block number or hash not provided")
|
|
}
|
|
|
|
var oldestAllowed uint64
|
|
if lastAcceptedNumber > queryWindow {
|
|
oldestAllowed = lastAcceptedNumber - queryWindow
|
|
}
|
|
if number >= oldestAllowed {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("block number %d is before the oldest allowed block number %d (window of %d blocks)",
|
|
number, oldestAllowed, queryWindow)
|
|
}
|