From 06c623b5c75989050057b060b3ef722431b4c290 Mon Sep 17 00:00:00 2001 From: zsfelfoldi Date: Fri, 24 Oct 2025 13:50:14 +0200 Subject: [PATCH] q --- restapi/exec_api.go | 215 ++++++++++++++++++++++++++++++++++++++++---- restapi/server.go | 10 --- 2 files changed, 198 insertions(+), 27 deletions(-) diff --git a/restapi/exec_api.go b/restapi/exec_api.go index 8777f40e2c..8fb3056d88 100644 --- a/restapi/exec_api.go +++ b/restapi/exec_api.go @@ -27,11 +27,23 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "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/rpc" "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 { apiBackend backend } @@ -40,17 +52,17 @@ func ExecutionAPI(server *Server, backend backend) API { api := execApiServer{apiBackend: backend} 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/blocks", 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/transaction", 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/receipt_by_index", 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/call", server.WrapHandler(api.handleCall, true, true, true)).Methods("POST") + router.HandleFunc("/eth/v1/exec/blocks/{blockid}", server.WrapHandler(api.handleBlocks, 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/{txhash}", server.WrapHandler(api.handleTransaction, 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/{blockid}", server.WrapHandler(api.handleReceiptByIndex, false, false, true)).Methods("GET") + router.HandleFunc("/eth/v1/exec/state/{blockid}", server.WrapHandler(api.handleState, 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/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/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) { return nil, "request timeout", http.StatusRequestTimeout } - if response[i].Data == nil { + if response[i].Data == nil || err != nil { return nil, "not available", http.StatusNotFound } 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { panic("TODO") } // Requires EIP-7745 diff --git a/restapi/server.go b/restapi/server.go index b4532615d6..8e682cd60d 100644 --- a/restapi/server.go +++ b/restapi/server.go @@ -25,13 +25,9 @@ import ( "time" "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/node" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/mux" ) @@ -41,12 +37,6 @@ type Server struct { 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) func NewServer(node *node.Node) *Server {