This commit is contained in:
zsfelfoldi 2025-10-24 13:50:14 +02:00
parent 7eac50fe88
commit 06c623b5c7
2 changed files with 198 additions and 27 deletions

View file

@ -27,11 +27,23 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks" "github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
type backend interface {
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)
GetPoolTransaction(txHash common.Hash) *types.Transaction
ChainConfig() *params.ChainConfig
}
type execApiServer struct { type execApiServer struct {
apiBackend backend apiBackend backend
} }
@ -40,17 +52,17 @@ func ExecutionAPI(server *Server, backend backend) API {
api := execApiServer{apiBackend: backend} api := execApiServer{apiBackend: backend}
return func(router *mux.Router) { return func(router *mux.Router) {
router.HandleFunc("/eth/v1/exec/headers/{blockid}", server.WrapHandler(api.handleHeaders, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/headers/{blockid}", server.WrapHandler(api.handleHeaders, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/blocks", server.WrapHandler(api.handleBlocks, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/blocks/{blockid}", server.WrapHandler(api.handleBlocks, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/block_receipts", server.WrapHandler(api.handleBlockReceipts, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/block_receipts/{blockid}", server.WrapHandler(api.handleBlockReceipts, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/transaction", server.WrapHandler(api.handleTransaction, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/transaction/{txhash}", server.WrapHandler(api.handleTransaction, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/transaction_by_index", server.WrapHandler(api.handleTxByIndex, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/transaction_by_index/{blockid}", server.WrapHandler(api.handleTxByIndex, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/receipt_by_index", server.WrapHandler(api.handleReceiptByIndex, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/receipt_by_index/{blockid}", server.WrapHandler(api.handleReceiptByIndex, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/state", server.WrapHandler(api.handleState, true, true, true)).Methods("POST") router.HandleFunc("/eth/v1/exec/state/{blockid}", server.WrapHandler(api.handleState, true, true, true)).Methods("POST")
router.HandleFunc("/eth/v1/exec/call", server.WrapHandler(api.handleCall, true, true, true)).Methods("POST") router.HandleFunc("/eth/v1/exec/call/{blockid}", server.WrapHandler(api.handleCall, true, true, true)).Methods("POST")
router.HandleFunc("/eth/v1/exec/send_transaction", server.WrapHandler(api.handleSendTransaction, true, true, true)).Methods("POST") router.HandleFunc("/eth/v1/exec/send_transaction", server.WrapHandler(api.handleSendTransaction, true, true, true)).Methods("POST")
router.HandleFunc("/eth/v1/exec/history", server.WrapHandler(api.handleHistory, false, false, true)).Methods("GET") /*router.HandleFunc("/eth/v1/exec/history", server.WrapHandler(api.handleHistory, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/transaction_position", server.WrapHandler(api.handleTxPosition, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/transaction_position", server.WrapHandler(api.handleTxPosition, false, false, true)).Methods("GET")
router.HandleFunc("/eth/v1/exec/logs", server.WrapHandler(api.handleLogs, false, false, true)).Methods("GET") router.HandleFunc("/eth/v1/exec/logs", server.WrapHandler(api.handleLogs, false, false, true)).Methods("GET")*/
} }
} }
@ -149,7 +161,7 @@ func (s *execApiServer) handleHeaders(ctx context.Context, values url.Values, va
if errors.Is(err, context.Canceled) { if errors.Is(err, context.Canceled) {
return nil, "request timeout", http.StatusRequestTimeout return nil, "request timeout", http.StatusRequestTimeout
} }
if response[i].Data == nil { if response[i].Data == nil || err != nil {
return nil, "not available", http.StatusNotFound return nil, "not available", http.StatusNotFound
} }
response[i].Version = s.forkName(response[i].Data) response[i].Version = s.forkName(response[i].Data)
@ -163,26 +175,195 @@ func (s *execApiServer) handleHeaders(ctx context.Context, values url.Values, va
} }
func (s *execApiServer) handleBlocks(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleBlocks(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") type blockResponse struct {
Version string `json:"version"`
Data *types.Block `json:"data"`
}
var (
amount int
response []blockResponse
err error
)
id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
if s := values.Get("amount"); s != "" {
amount, err = strconv.Atoi(s)
if err != nil || amount <= 0 {
return nil, "invalid amount", http.StatusBadRequest
}
} else {
amount = 1
}
response = make([]blockResponse, amount)
for i := amount - 1; i >= 0; i-- {
if id.isHash() {
response[i].Data, err = s.apiBackend.BlockByHash(ctx, id.hash)
} else {
response[i].Data, err = s.apiBackend.BlockByNumber(ctx, rpc.BlockNumber(id.number))
}
if errors.Is(err, context.Canceled) {
return nil, "request timeout", http.StatusRequestTimeout
}
if response[i].Data == nil || err != nil {
return nil, "not available", http.StatusNotFound
}
response[i].Version = s.forkName(response[i].Data.Header())
if response[i].Data.NumberU64() == 0 {
response = response[i:]
break
}
id = blockId{hash: response[i].Data.ParentHash()}
}
return response, "", 0
} }
func (s *execApiServer) handleBlockReceipts(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleBlockReceipts(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") type blockReceiptsResponse struct {
Version string `json:"version"`
Data types.Receipts `json:"data"`
}
var (
amount int
response []blockReceiptsResponse
err error
)
id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
if s := values.Get("amount"); s != "" {
amount, err = strconv.Atoi(s)
if err != nil || amount <= 0 {
return nil, "invalid amount", http.StatusBadRequest
}
} else {
amount = 1
}
response = make([]blockReceiptsResponse, amount)
for i := amount - 1; i >= 0; i-- {
var header *types.Header
if id.isHash() {
header, err = s.apiBackend.HeaderByHash(ctx, id.hash)
} else {
header, err = s.apiBackend.HeaderByNumber(ctx, rpc.BlockNumber(id.number))
}
if header != nil && err == nil {
response[i].Data, err = s.apiBackend.GetReceipts(ctx, header.Hash())
}
if errors.Is(err, context.Canceled) {
return nil, "request timeout", http.StatusRequestTimeout
}
if response[i].Data == nil || err != nil {
return nil, "not available", http.StatusNotFound
}
response[i].Version = s.forkName(header)
if header.Number.Uint64() == 0 {
response = response[i:]
break
}
id = blockId{hash: header.ParentHash}
}
return response, "", 0
} }
func (s *execApiServer) handleTransaction(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleTransaction(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") var txHash common.Hash
if hex, err := hexutil.Decode(vars["txhash"]); err == nil {
if len(hex) != common.HashLength {
return nil, "invalid transaction hash", http.StatusBadRequest
}
copy(txHash[:], hex)
}
_, tx, _, _, _ := s.apiBackend.GetCanonicalTransaction(txHash)
if tx == nil {
tx = s.apiBackend.GetPoolTransaction(txHash)
}
if tx == nil {
return nil, "not available", http.StatusNotFound
}
return tx, "", 0
} }
func (s *execApiServer) handleTxByIndex(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleTxByIndex(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") type txProof struct {
Index uint64 `json:"index"`
Transaction *types.Transaction `json:"transaction" rlp:"-"`
Proof []hexutil.Bytes `json:"proof"`
}
var response struct {
Version string `json:"version"`
Data types.Receipts `json:"data"`
}
id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
indices := values["indices"]
if len(indices) == 0 {
return nil, "empty transaction index list", http.StatusBadRequest
}
response.Data = make([]txProof, len(indices))
for i, str := range indicesStr {
if number, err := strconv.ParseUint(str, 10, 64); err == nil {
indices[i] = number
} else {
return nil, "invalid transaction index", http.StatusBadRequest
}
}
var (
block *types.Block
err error
)
if id.isHash() {
block, err = s.apiBackend.BlockByHash(ctx, id.hash)
} else {
block, err = s.apiBackend.BlockByNumber(ctx, rpc.BlockNumber(id.number))
}
if errors.Is(err, context.Canceled) {
return nil, "request timeout", http.StatusRequestTimeout
}
if block == nil || err != nil {
return nil, "not available", http.StatusNotFound
}
response[i].Version = s.forkName(block.Header())
t := trie.NewStackTrie(nil)
if types.DeriveSha(block.Transactions(), t) != block.TransactionsRoot() {
log.Error("")
return nil, "transactions root mismatch", http.StatusInternalServerError
}
var indexBuf []byte
for _, txIndex := range indices {
indexBuf = rlp.AppendUint64(indexBuf[:0], txIndex)
t.Prove(indexBuf, proofWriter)
}
} }
func (s *execApiServer) handleReceiptByIndex(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleReceiptByIndex(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
} }
func (s *execApiServer) handleState(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleState(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
} }
func (s *execApiServer) handleCall(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleCall(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") id, ok := getBlockId(vars["blockid"])
if !ok {
return nil, "invalid block id", http.StatusBadRequest
}
} }
func (s *execApiServer) handleHistory(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) { func (s *execApiServer) handleHistory(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) {
panic("TODO") panic("TODO")
} // Requires EIP-7745 } // Requires EIP-7745

View file

@ -25,13 +25,9 @@ import (
"time" "time"
"github.com/elnormous/contenttype" "github.com/elnormous/contenttype"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -41,12 +37,6 @@ type Server struct {
type API func(*mux.Router) type API func(*mux.Router)
type backend interface {
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
ChainConfig() *params.ChainConfig
}
type WrappedHandler func(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int) type WrappedHandler func(ctx context.Context, values url.Values, vars map[string]string, decodeBody func(*any) error) (any, string, int)
func NewServer(node *node.Node) *Server { func NewServer(node *node.Node) *Server {