From cf726dbc714b7695d3fd98649d35f0483d81f961 Mon Sep 17 00:00:00 2001 From: Ryan Tinianov Date: Wed, 30 Oct 2024 16:34:14 -0400 Subject: [PATCH] Fix the log event trigger to match the schema. (#15035) * Fix the log event trigger to match the schema. * Decode the bytes instead and add an 0x prefix * Fix wrapping the log.Data as values.Map and ensure working tests * Fixed lint errors * Fixed more lint errors --------- Co-authored-by: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> --- .../logeventcap/event_trigger-schema.json | 3 +- .../logeventcap/event_trigger_generated.go | 23 +++-- .../capabilities/triggers/logevent/trigger.go | 27 +++++- .../test_server/test_server.go | 89 +++++++++++++++++++ 4 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 core/scripts/gateway/web_api_trigger/test_server/test_server.go diff --git a/core/capabilities/triggers/logevent/logeventcap/event_trigger-schema.json b/core/capabilities/triggers/logevent/logeventcap/event_trigger-schema.json index a60d8823582..317b755febb 100644 --- a/core/capabilities/triggers/logevent/logeventcap/event_trigger-schema.json +++ b/core/capabilities/triggers/logevent/logeventcap/event_trigger-schema.json @@ -17,7 +17,8 @@ "type": "integer", "minimum": 0 } - } + }, + "required": ["Height", "Hash", "Timestamp"] }, "config": { "type": "object", diff --git a/core/capabilities/triggers/logevent/logeventcap/event_trigger_generated.go b/core/capabilities/triggers/logevent/logeventcap/event_trigger_generated.go index 23376958309..32c934ea1b4 100644 --- a/core/capabilities/triggers/logevent/logeventcap/event_trigger_generated.go +++ b/core/capabilities/triggers/logevent/logeventcap/event_trigger_generated.go @@ -85,26 +85,39 @@ func (j *Config) UnmarshalJSON(b []byte) error { type Head struct { // Hash corresponds to the JSON schema field "Hash". - Hash *string `json:"Hash,omitempty" yaml:"Hash,omitempty" mapstructure:"Hash,omitempty"` + Hash string `json:"Hash" yaml:"Hash" mapstructure:"Hash"` // Height corresponds to the JSON schema field "Height". - Height *string `json:"Height,omitempty" yaml:"Height,omitempty" mapstructure:"Height,omitempty"` + Height string `json:"Height" yaml:"Height" mapstructure:"Height"` // Timestamp corresponds to the JSON schema field "Timestamp". - Timestamp *uint64 `json:"Timestamp,omitempty" yaml:"Timestamp,omitempty" mapstructure:"Timestamp,omitempty"` + Timestamp uint64 `json:"Timestamp" yaml:"Timestamp" mapstructure:"Timestamp"` } // UnmarshalJSON implements json.Unmarshaler. func (j *Head) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["Hash"]; raw != nil && !ok { + return fmt.Errorf("field Hash in Head: required") + } + if _, ok := raw["Height"]; raw != nil && !ok { + return fmt.Errorf("field Height in Head: required") + } + if _, ok := raw["Timestamp"]; raw != nil && !ok { + return fmt.Errorf("field Timestamp in Head: required") + } type Plain Head var plain Plain if err := json.Unmarshal(b, &plain); err != nil { return err } - if plain.Hash != nil && len(*plain.Hash) < 1 { + if len(plain.Hash) < 1 { return fmt.Errorf("field %s length: must be >= %d", "Hash", 1) } - if plain.Height != nil && len(*plain.Height) < 1 { + if len(plain.Height) < 1 { return fmt.Errorf("field %s length: must be >= %d", "Height", 1) } *j = Head(plain) diff --git a/core/capabilities/triggers/logevent/trigger.go b/core/capabilities/triggers/logevent/trigger.go index 1ce8ee5fd78..517e4a94683 100644 --- a/core/capabilities/triggers/logevent/trigger.go +++ b/core/capabilities/triggers/logevent/trigger.go @@ -180,12 +180,35 @@ func (l *logEventTrigger) listen() { // Create log event trigger capability response func createTriggerResponse(log types.Sequence, version string) capabilities.TriggerResponse { - wrappedPayload, err := values.WrapMap(log) + dataAsValuesMap, err := values.WrapMap(log.Data) if err != nil { return capabilities.TriggerResponse{ - Err: fmt.Errorf("error wrapping trigger event: %s", err), + Err: fmt.Errorf("error decoding log data as values.Map: %w", err), } } + dataAsMap := map[string]any{} + err = dataAsValuesMap.UnwrapTo(&dataAsMap) + if err != nil { + return capabilities.TriggerResponse{ + Err: fmt.Errorf("error decoding log data as map[string]any: %w", err), + } + } + + wrappedPayload, err := values.WrapMap(&logeventcap.Output{ + Cursor: log.Cursor, + Data: dataAsMap, + Head: logeventcap.Head{ + Hash: fmt.Sprintf("0x%x", log.Hash), + Height: log.Height, + Timestamp: log.Timestamp, + }, + }) + if err != nil { + return capabilities.TriggerResponse{ + Err: fmt.Errorf("error wrapping trigger event: %w", err), + } + } + return capabilities.TriggerResponse{ Event: capabilities.TriggerEvent{ TriggerType: version, diff --git a/core/scripts/gateway/web_api_trigger/test_server/test_server.go b/core/scripts/gateway/web_api_trigger/test_server/test_server.go new file mode 100644 index 00000000000..287d604e899 --- /dev/null +++ b/core/scripts/gateway/web_api_trigger/test_server/test_server.go @@ -0,0 +1,89 @@ +package main + +import ( + "fmt" + "io" + "net/http" + "time" +) + +func handler(w http.ResponseWriter, r *http.Request) { + // Log request method and URL + fmt.Printf("Received %s request for %s\n", r.Method, r.URL.Path) + + // Handle GET requests + if r.Method == http.MethodGet { + fmt.Println("GET request received") + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte("GET request received")) + if err != nil { + http.Error(w, "could not write request body", http.StatusInternalServerError) + return + } + } + + // Handle POST requests + if r.Method == http.MethodPost { + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Could not read request body", http.StatusInternalServerError) + return + } + fmt.Printf("POST request body: %s\n", string(body)) + + w.WriteHeader(http.StatusOK) + } +} + +func lockHandler(w http.ResponseWriter, r *http.Request) { + // Log request method and URL + fmt.Printf("Received %s request for %s\n", r.Method, r.URL.Path) + + // Handle POST requests + if r.Method == http.MethodPost { + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Could not read request body", http.StatusInternalServerError) + return + } + fmt.Printf("Assets locked. E2E ID: %s\n", string(body)) + + w.WriteHeader(http.StatusOK) + } +} + +func unlockHandler(w http.ResponseWriter, r *http.Request) { + // Log request method and URL + fmt.Printf("Received %s request for %s\n", r.Method, r.URL.Path) + + // Handle POST requests + if r.Method == http.MethodPost { + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Could not read request body", http.StatusInternalServerError) + return + } + fmt.Printf("Assets unlocked. Settlement E2E ID: %s\n", string(body)) + + w.WriteHeader(http.StatusOK) + } +} + +func main() { + // Register the handler for all incoming requests + http.HandleFunc("/", handler) + http.HandleFunc("/lock", lockHandler) + http.HandleFunc("/unlock", unlockHandler) + + // Listen on port 1000 + port := ":1000" + fmt.Printf("Server listening on port %s\n", port) + server := &http.Server{ + Addr: port, + ReadHeaderTimeout: 30 * time.Second, + } + err := server.ListenAndServe() + if err != nil { + panic(err) + } +}