2023-04-18 21:57:55 +03:00
|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2023-05-04 18:21:48 +03:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ethereum-optimism/optimism/proxyd"
|
2023-04-18 21:57:55 +03:00
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
type MethodTemplate struct {
|
2024-06-26 23:54:53 +03:00
|
|
|
Method string `yaml:"method"`
|
|
|
|
Block string `yaml:"block"`
|
|
|
|
Response string `yaml:"response"`
|
|
|
|
ResponseCode int `yaml:"response_code"`
|
2023-04-18 21:57:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type MockedHandler struct {
|
|
|
|
Overrides []*MethodTemplate
|
|
|
|
Autoload bool
|
|
|
|
AutoloadFile string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *MockedHandler) Serve(port int) error {
|
|
|
|
r := mux.NewRouter()
|
|
|
|
r.HandleFunc("/", mh.Handler)
|
|
|
|
http.Handle("/", r)
|
|
|
|
fmt.Printf("starting server up on :%d serving MockedResponsesFile %s\n", port, mh.AutoloadFile)
|
|
|
|
err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
|
|
|
|
|
|
|
|
if errors.Is(err, http.ErrServerClosed) {
|
|
|
|
fmt.Printf("server closed\n")
|
|
|
|
} else if err != nil {
|
|
|
|
fmt.Printf("error starting server: %s\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *MockedHandler) Handler(w http.ResponseWriter, req *http.Request) {
|
|
|
|
body, err := io.ReadAll(req.Body)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error reading request: %v\n", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var template []*MethodTemplate
|
|
|
|
if mh.Autoload {
|
|
|
|
template = append(template, mh.LoadFromFile(mh.AutoloadFile)...)
|
|
|
|
}
|
|
|
|
if mh.Overrides != nil {
|
|
|
|
template = append(template, mh.Overrides...)
|
|
|
|
}
|
|
|
|
|
2023-05-04 18:21:48 +03:00
|
|
|
batched := proxyd.IsBatch(body)
|
|
|
|
var requests []map[string]interface{}
|
|
|
|
if batched {
|
|
|
|
err = json.Unmarshal(body, &requests)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error reading request: %v\n", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var j map[string]interface{}
|
|
|
|
err = json.Unmarshal(body, &j)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error reading request: %v\n", err)
|
|
|
|
}
|
|
|
|
requests = append(requests, j)
|
2023-04-18 21:57:55 +03:00
|
|
|
}
|
|
|
|
|
2023-05-04 18:21:48 +03:00
|
|
|
var responses []string
|
|
|
|
for _, r := range requests {
|
|
|
|
method := r["method"]
|
|
|
|
block := ""
|
2023-10-19 21:29:24 +03:00
|
|
|
if method == "eth_getBlockByNumber" || method == "debug_getRawReceipts" {
|
2023-05-04 18:21:48 +03:00
|
|
|
block = (r["params"].([]interface{})[0]).(string)
|
2023-04-18 21:57:55 +03:00
|
|
|
}
|
2023-05-04 18:21:48 +03:00
|
|
|
|
|
|
|
var selectedResponse string
|
|
|
|
for _, r := range template {
|
|
|
|
if r.Method == method && r.Block == block {
|
|
|
|
selectedResponse = r.Response
|
2024-06-26 23:54:53 +03:00
|
|
|
if r.ResponseCode != 0 {
|
|
|
|
w.WriteHeader(r.ResponseCode)
|
|
|
|
}
|
2023-05-04 18:21:48 +03:00
|
|
|
}
|
2023-04-18 21:57:55 +03:00
|
|
|
}
|
2023-05-04 18:21:48 +03:00
|
|
|
if selectedResponse != "" {
|
2023-06-01 23:16:40 +03:00
|
|
|
var rpcRes proxyd.RPCRes
|
|
|
|
err = json.Unmarshal([]byte(selectedResponse), &rpcRes)
|
2023-06-01 23:36:13 +03:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2023-06-01 23:16:40 +03:00
|
|
|
idJson, _ := json.Marshal(r["id"])
|
|
|
|
rpcRes.ID = idJson
|
|
|
|
res, _ := json.Marshal(rpcRes)
|
|
|
|
responses = append(responses, string(res))
|
2023-05-04 18:21:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resBody := ""
|
|
|
|
if batched {
|
|
|
|
resBody = "[" + strings.Join(responses, ",") + "]"
|
2023-05-26 07:37:47 +03:00
|
|
|
} else if len(responses) > 0 {
|
2023-05-04 18:21:48 +03:00
|
|
|
resBody = responses[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = fmt.Fprint(w, resBody)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error writing response: %v\n", err)
|
2023-04-18 21:57:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *MockedHandler) LoadFromFile(file string) []*MethodTemplate {
|
|
|
|
contents, err := os.ReadFile(file)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error reading MockedResponsesFile: %v\n", err)
|
|
|
|
}
|
|
|
|
var template []*MethodTemplate
|
|
|
|
err = yaml.Unmarshal(contents, &template)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error reading MockedResponsesFile: %v\n", err)
|
|
|
|
}
|
|
|
|
return template
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *MockedHandler) AddOverride(template *MethodTemplate) {
|
|
|
|
mh.Overrides = append(mh.Overrides, template)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mh *MockedHandler) ResetOverrides() {
|
|
|
|
mh.Overrides = make([]*MethodTemplate, 0)
|
|
|
|
}
|