diff --git a/.github/workflows/golangci_lint.yml b/.github/workflows/golangci_lint.yml index 22ef02836..81b4839fe 100644 --- a/.github/workflows/golangci_lint.yml +++ b/.github/workflows/golangci_lint.yml @@ -13,5 +13,5 @@ jobs: - name: golangci-lint uses: smartcontractkit/.github/actions/ci-lint-go@2ac9d97a83a5edded09af7fcf4ea5bce7a4473a4 # v0.2.6 with: - golangci-lint-version: v1.61.0 + golangci-lint-version: v1.62.2 \ No newline at end of file diff --git a/.tool-versions b/.tool-versions index 6b6bb428c..167471122 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,5 +1,5 @@ -golang 1.22.7 +golang 1.23.3 protoc 25.1 protoc-gen-go-grpc 1.3.0 -golangci-lint 1.61.0 +golangci-lint 1.62.2 mockery 2.43.2 diff --git a/Makefile b/Makefile index 8955675da..06a572d67 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ generate: mockery install-protoc gomods mockery .PHONY: lint-workspace lint -GOLANGCI_LINT_VERSION := 1.60.1 +GOLANGCI_LINT_VERSION := 1.62.2 GOLANGCI_LINT_COMMON_OPTS := --max-issues-per-linter 0 --max-same-issues 0 GOLANGCI_LINT_DIRECTORY := ./golangci-lint diff --git a/go.mod b/go.mod index d27908094..68a59eed3 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/smartcontractkit/chainlink-common -go 1.22.0 - -toolchain go1.22.7 +go 1.23.3 require ( github.com/andybalholm/brotli v1.1.0 diff --git a/observability-lib/README.md b/observability-lib/README.md index 27b0dad0f..8c4e4d249 100644 --- a/observability-lib/README.md +++ b/observability-lib/README.md @@ -15,8 +15,7 @@ The observability-lib is structured as follows: ```shell observability-lib/ api/ # Grafana HTTP API Client to interact with resources - cmd/ # CLI to interact deploy or generateJSON from dashboards defined in folder below - dashboards/ # Dashboards definitions + cmd/ # CLI grafana/ # grafana-foundations-sdk abstraction to manipulate grafana resources ``` @@ -89,43 +88,56 @@ func main() { ``` -More advanced examples can be found in the [dashboards](./dashboards) folder : -- [DON OCR](./dashboards/atlas-don/component.go) -- [Capabilities](./dashboards/capabilities/component.go) -- [Node General](./dashboards/core-node/component.go) -- [Node Components](./dashboards/core-node-components/component.go) -- [Kubernetes Resources](./dashboards/k8s-resources/component.go) -- [NOP OCR Health](./dashboards/nop-ocr/component.go) - ## Cmd Usage -The CLI can be used to : -- Deploy dashboards and alerts to grafana -- Generate JSON from dashboards defined in the `dashboards` folder +CLI to manipulate grafana resources + +### Contact Point -`func NewDashboard(props *Props)` in each [dashboards](./dashboards) packages is called from [cmd](./cmd/builder.go) to deploy or generate JSON from the dashboard. +#### List -Example to deploy a dashboard to grafana instance using URL and token: ```shell -make build -./observability-lib deploy \ - --dashboard-name DashboardName \ - --dashboard-folder FolderName \ - --grafana-url $GRAFANA_URL \ - --grafana-token $GRAFANA_TOKEN \ - --type core-node \ - --platform kubernetes \ - --metrics-datasource Prometheus +./observability-lib api contact-point list \ + --grafana-url http://localhost:3000 \ + --grafana-token ``` -To see how to get a grafana token you can check this [page](https://grafana.com/docs/grafana/latest/administration/service-accounts/) -Example to generate JSON from a dashboard defined in the `dashboards` folder: +#### Delete + ```shell -make build -./observability-lib generate \ - --dashboard-name DashboardName \ - --type core-node-components \ - --platform kubernetes +./observability-lib api contact-point delete \ + --grafana-url http://localhost:3000 \ + --grafana-token +``` + +### Dashboard + +#### Delete + +```shell +./observability-lib api dashboard delete \ + --grafana-url http://localhost:3000 \ + --grafana-token +``` + +### Notification Policy + +#### List + +```shell +./observability-lib api notification-policy list \ + --grafana-url http://localhost:3000 \ + --grafana-token +``` + +#### Delete + +```shell +./observability-lib api notification-policy delete \ + --grafana-url http://localhost:3000 \ + --grafana-token \ + --matchers key,=,value \ + --matchers key2,=,value2 ``` ## Makefile Usage diff --git a/observability-lib/api/notification-policy.go b/observability-lib/api/notification-policy.go index 5792c1a8c..5812e81d2 100644 --- a/observability-lib/api/notification-policy.go +++ b/observability-lib/api/notification-policy.go @@ -29,6 +29,23 @@ func objectMatchersEqual(a alerting.ObjectMatchers, b alerting.ObjectMatchers) b return true } +func PrintPolicyTree(policy alerting.NotificationPolicy, depth int) { + if depth == 0 { + fmt.Printf("| Root Policy | Receiver: %s\n", *policy.Receiver) + } + + for _, notificationPolicy := range policy.Routes { + for i := 0; i < depth; i++ { + fmt.Print("--") + } + fmt.Printf("| Matchers %s | Receiver: %s\n", *notificationPolicy.ObjectMatchers, *notificationPolicy.Receiver) + + if notificationPolicy.Routes != nil { + PrintPolicyTree(notificationPolicy, depth+1) + } + } +} + func policyExist(parent alerting.NotificationPolicy, newNotificationPolicy alerting.NotificationPolicy) bool { for _, notificationPolicy := range parent.Routes { matchersEqual := false @@ -40,24 +57,89 @@ func policyExist(parent alerting.NotificationPolicy, newNotificationPolicy alert return true } if notificationPolicy.Routes != nil { - policyExist(notificationPolicy, newNotificationPolicy) + return policyExist(notificationPolicy, newNotificationPolicy) + } + } + return false +} + +func updateInPlace(parent *alerting.NotificationPolicy, newNotificationPolicy alerting.NotificationPolicy) bool { + for key, notificationPolicy := range parent.Routes { + matchersEqual := false + if notificationPolicy.ObjectMatchers != nil { + matchersEqual = objectMatchersEqual(*notificationPolicy.ObjectMatchers, *newNotificationPolicy.ObjectMatchers) + } + receiversEqual := reflect.DeepEqual(notificationPolicy.Receiver, newNotificationPolicy.Receiver) + if matchersEqual && receiversEqual { + parent.Routes[key] = newNotificationPolicy + return true + } + if notificationPolicy.Routes != nil { + return updateInPlace(&parent.Routes[key], newNotificationPolicy) + } + } + return false +} + +func deleteInPlace(parent *alerting.NotificationPolicy, newNotificationPolicy alerting.NotificationPolicy) bool { + for key, notificationPolicy := range parent.Routes { + matchersEqual := false + if notificationPolicy.ObjectMatchers != nil { + matchersEqual = objectMatchersEqual(*notificationPolicy.ObjectMatchers, *newNotificationPolicy.ObjectMatchers) + } + receiversEqual := reflect.DeepEqual(notificationPolicy.Receiver, newNotificationPolicy.Receiver) + if matchersEqual && receiversEqual { + if len(parent.Routes) == 1 { + parent.Routes = nil + return true + } else if len(parent.Routes) > 1 { + parent.Routes = append(parent.Routes[:key], parent.Routes[key+1:]...) + return true + } else { + return false + } + } + if notificationPolicy.Routes != nil { + return deleteInPlace(&parent.Routes[key], newNotificationPolicy) } } return false } +// DeleteNestedPolicy Delete Nested Policy from Notification Policy Tree +func (c *Client) DeleteNestedPolicy(newNotificationPolicy alerting.NotificationPolicy) error { + notificationPolicyTreeResponse, _, err := c.GetNotificationPolicy() + if err != nil { + return err + } + notificationPolicyTree := alerting.NotificationPolicy(notificationPolicyTreeResponse) + if !policyExist(notificationPolicyTree, newNotificationPolicy) { + return fmt.Errorf("notification policy not found") + } + deleteInPlace(¬ificationPolicyTree, newNotificationPolicy) + _, _, errPutNotificationPolicy := c.PutNotificationPolicy(notificationPolicyTree) + if errPutNotificationPolicy != nil { + return errPutNotificationPolicy + } + return nil +} + // AddNestedPolicy Add Nested Policy to Notification Policy Tree func (c *Client) AddNestedPolicy(newNotificationPolicy alerting.NotificationPolicy) error { - notificationPolicyTree, _, err := c.GetNotificationPolicy() + notificationPolicyTreeResponse, _, err := c.GetNotificationPolicy() + notificationPolicyTree := alerting.NotificationPolicy(notificationPolicyTreeResponse) + if err != nil { return err } - if !policyExist(alerting.NotificationPolicy(notificationPolicyTree), newNotificationPolicy) { + if !policyExist(notificationPolicyTree, newNotificationPolicy) { notificationPolicyTree.Routes = append(notificationPolicyTree.Routes, newNotificationPolicy) - _, _, errPutNotificationPolicy := c.PutNotificationPolicy(alerting.NotificationPolicy(notificationPolicyTree)) - if errPutNotificationPolicy != nil { - return errPutNotificationPolicy - } + } else { + updateInPlace(¬ificationPolicyTree, newNotificationPolicy) + } + _, _, errPutNotificationPolicy := c.PutNotificationPolicy(notificationPolicyTree) + if errPutNotificationPolicy != nil { + return errPutNotificationPolicy } return nil } diff --git a/observability-lib/api/notification-policy_test.go b/observability-lib/api/notification-policy_test.go index 16ead9063..3891a0458 100644 --- a/observability-lib/api/notification-policy_test.go +++ b/observability-lib/api/notification-policy_test.go @@ -7,6 +7,10 @@ import ( "github.com/stretchr/testify/require" ) +func Pointer[T any](d T) *T { + return &d +} + func TestObjectMatchersEqual(t *testing.T) { t.Run("returns true if the two object matchers are equal", func(t *testing.T) { a := alerting.ObjectMatchers{{"team", "=", "chainlink"}} @@ -44,3 +48,218 @@ func TestObjectMatchersEqual(t *testing.T) { require.False(t, result) }) } + +func TestPolicyExists(t *testing.T) { + t.Run("policyExists return true if policy exists", func(t *testing.T) { + notificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + }, + }, + }, + }, + } + + newNotificationPolicy := alerting.NotificationPolicy{ + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + } + result := policyExist(*notificationPolicyTree, newNotificationPolicy) + require.True(t, result) + }) + + t.Run("policyExists return false if policy does not exists", func(t *testing.T) { + notificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + }, + }, + }, + }, + } + + newNotificationPolicy := alerting.NotificationPolicy{ + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"key", "=", "value"}, + }, + } + result := policyExist(*notificationPolicyTree, newNotificationPolicy) + require.False(t, result) + }) + + t.Run("updateInPlace should update notification policy if already exists", func(t *testing.T) { + notificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + }, + }, + }, + }, + } + + newNotificationPolicy := alerting.NotificationPolicy{ + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + Continue: Pointer(true), + } + + expectedNotificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + Continue: Pointer(true), + }, + }, + }, + }, + } + + updateInPlace(notificationPolicyTree, newNotificationPolicy) + require.Equal(t, expectedNotificationPolicyTree, notificationPolicyTree) + }) + + t.Run("deleteInPlace should delete notification policy if exists", func(t *testing.T) { + notificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + }, + { + Receiver: Pointer("slack2"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink2"}, + }, + }, + { + Receiver: Pointer("slack3"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink3"}, + }, + }, + }, + } + + newNotificationPolicy := alerting.NotificationPolicy{ + Receiver: Pointer("slack2"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink2"}, + }, + } + + expectedNotificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + }, + { + Receiver: Pointer("slack3"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink3"}, + }, + }, + }, + } + deleteInPlace(notificationPolicyTree, newNotificationPolicy) + require.Equal(t, expectedNotificationPolicyTree, notificationPolicyTree) + }) + + t.Run("deleteInPlace should delete notification policy if exists", func(t *testing.T) { + notificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + }, + }, + }, + }, + } + + newNotificationPolicy := alerting.NotificationPolicy{ + Receiver: Pointer("pagerduty"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"env", "=", "production"}, + }, + } + + expectedNotificationPolicyTree := &alerting.NotificationPolicy{ + Receiver: Pointer("grafana-default-email"), + Routes: []alerting.NotificationPolicy{ + { + Receiver: Pointer("slack"), + ObjectMatchers: &alerting.ObjectMatchers{ + {"team", "=", "chainlink"}, + }, + }, + }, + } + deleteInPlace(notificationPolicyTree, newNotificationPolicy) + require.Equal(t, expectedNotificationPolicyTree, notificationPolicyTree) + }) + +} diff --git a/observability-lib/api/rule-group.go b/observability-lib/api/rule-group.go new file mode 100644 index 000000000..1d4bde5f3 --- /dev/null +++ b/observability-lib/api/rule-group.go @@ -0,0 +1,33 @@ +package api + +import ( + "fmt" + + "github.com/go-resty/resty/v2" + "github.com/grafana/grafana-foundation-sdk/go/alerting" +) + +type UpdateAlertRuleGroupResponse struct{} + +// UpdateAlertRuleGroup Update a specific alert rule group +func (c *Client) UpdateAlertRuleGroup(folderUID string, alertRuleGroup alerting.RuleGroup) (UpdateAlertRuleGroupResponse, *resty.Response, error) { + var grafanaResp UpdateAlertRuleGroupResponse + + resp, err := c.resty.R(). + SetHeader("Content-Type", "application/json"). + SetHeader("X-Disable-Provenance", "true"). + SetBody(alertRuleGroup). + SetResult(&grafanaResp). + Put(fmt.Sprintf("/api/v1/provisioning/folder/%s/rule-groups/%s", folderUID, *alertRuleGroup.Title)) + + if err != nil { + return UpdateAlertRuleGroupResponse{}, resp, fmt.Errorf("error making API request: %w", err) + } + + statusCode := resp.StatusCode() + if statusCode != 200 { + return UpdateAlertRuleGroupResponse{}, resp, fmt.Errorf("error updating alert rule group, received unexpected status code %d: %s", statusCode, resp.String()) + } + + return grafanaResp, resp, nil +} diff --git a/observability-lib/api/rule.go b/observability-lib/api/rule.go index d5546752d..ddbf9e718 100644 --- a/observability-lib/api/rule.go +++ b/observability-lib/api/rule.go @@ -25,6 +25,22 @@ func (c *Client) GetAlertRulesByDashboardUID(dashboardUID string) (GetAllAlertRu return alerts, nil } +// GetAlertRulesByFolderUIDAndGroupName Get alert rules by folder UID and GroupName +func (c *Client) GetAlertRulesByFolderUIDAndGroupName(folderUID string, ruleGroupName string) (GetAllAlertRulesResponse, error) { + var alerts []alerting.Rule + + alertsRule, _, err := c.GetAlertRules() + if err != nil { + return nil, err + } + for _, rule := range alertsRule { + if rule.FolderUID != "" && (rule.FolderUID == folderUID) && (rule.RuleGroup == ruleGroupName) { + alerts = append(alerts, rule) + } + } + return alerts, nil +} + // GetAlertRules Get all alert rules func (c *Client) GetAlertRules() (GetAllAlertRulesResponse, *resty.Response, error) { var grafanaResp GetAllAlertRulesResponse diff --git a/observability-lib/cmd/api/api.go b/observability-lib/cmd/api/api.go new file mode 100644 index 000000000..d6c407f76 --- /dev/null +++ b/observability-lib/cmd/api/api.go @@ -0,0 +1,31 @@ +package api + +import ( + "github.com/smartcontractkit/chainlink-common/observability-lib/cmd/api/contact_point" + "github.com/smartcontractkit/chainlink-common/observability-lib/cmd/api/dashboard" + "github.com/smartcontractkit/chainlink-common/observability-lib/cmd/api/notification_policy" + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "api [resources]", + Short: "Select resources to perform actions", +} + +func init() { + Cmd.AddCommand(contact_point.Cmd) + Cmd.AddCommand(dashboard.Cmd) + Cmd.AddCommand(notification_policy.Cmd) + + Cmd.PersistentFlags().String("grafana-url", "", "Grafana URL") + errURL := Cmd.MarkPersistentFlagRequired("grafana-url") + if errURL != nil { + panic(errURL) + } + + Cmd.PersistentFlags().String("grafana-token", "", "Grafana API token") + errToken := Cmd.MarkPersistentFlagRequired("grafana-token") + if errToken != nil { + panic(errToken) + } +} diff --git a/observability-lib/cmd/api/contact_point/contact-point.go b/observability-lib/cmd/api/contact_point/contact-point.go new file mode 100644 index 000000000..e32f202c6 --- /dev/null +++ b/observability-lib/cmd/api/contact_point/contact-point.go @@ -0,0 +1,14 @@ +package contact_point + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "contact-point [actions]", + Short: "Perform actions on contact point", +} + +func init() { + Cmd.AddCommand(listCmd, deleteCmd) +} diff --git a/observability-lib/cmd/api/contact_point/delete.go b/observability-lib/cmd/api/contact_point/delete.go new file mode 100644 index 000000000..01af1940e --- /dev/null +++ b/observability-lib/cmd/api/contact_point/delete.go @@ -0,0 +1,35 @@ +package contact_point + +import ( + "errors" + + "github.com/smartcontractkit/chainlink-common/observability-lib/api" + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete [name]", + Short: "Delete contact point by name", + RunE: func(cmd *cobra.Command, args []string) error { + grafanaClient := api.NewClient( + cmd.Flag("grafana-url").Value.String(), + cmd.Flag("grafana-token").Value.String(), + ) + + contactPoint, err := grafanaClient.GetContactPointByName(args[0]) + if err != nil { + return err + } + + if contactPoint == nil { + return errors.New("contact point not found") + } + + _, _, errDelete := grafanaClient.DeleteContactPoint(*contactPoint.Uid) + if errDelete != nil { + return errDelete + } + + return nil + }, +} diff --git a/observability-lib/cmd/api/contact_point/list.go b/observability-lib/cmd/api/contact_point/list.go new file mode 100644 index 000000000..ca62b79f7 --- /dev/null +++ b/observability-lib/cmd/api/contact_point/list.go @@ -0,0 +1,28 @@ +package contact_point + +import ( + "github.com/smartcontractkit/chainlink-common/observability-lib/api" + "github.com/spf13/cobra" +) + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List contact point", + RunE: func(cmd *cobra.Command, args []string) error { + grafanaClient := api.NewClient( + cmd.Flag("grafana-url").Value.String(), + cmd.Flag("grafana-token").Value.String(), + ) + + contactPoints, _, err := grafanaClient.GetContactPoints() + if err != nil { + return err + } + + for _, contactPoint := range contactPoints { + cmd.Printf("| Name: %s | UID: %s\n", *contactPoint.Name, *contactPoint.Uid) + } + + return nil + }, +} diff --git a/observability-lib/cmd/api/dashboard/dashboard.go b/observability-lib/cmd/api/dashboard/dashboard.go new file mode 100644 index 000000000..8c46d0abe --- /dev/null +++ b/observability-lib/cmd/api/dashboard/dashboard.go @@ -0,0 +1,14 @@ +package dashboard + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "dashboard [actions]", + Short: "Perform actions on dashboard", +} + +func init() { + Cmd.AddCommand(deleteCmd) +} diff --git a/observability-lib/cmd/api/dashboard/delete.go b/observability-lib/cmd/api/dashboard/delete.go new file mode 100644 index 000000000..5b40f41a5 --- /dev/null +++ b/observability-lib/cmd/api/dashboard/delete.go @@ -0,0 +1,35 @@ +package dashboard + +import ( + "errors" + + "github.com/smartcontractkit/chainlink-common/observability-lib/api" + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete [name]", + Short: "Delete dashboard by name", + RunE: func(cmd *cobra.Command, args []string) error { + grafanaClient := api.NewClient( + cmd.Flag("grafana-url").Value.String(), + cmd.Flag("grafana-token").Value.String(), + ) + + delDashboard, _, err := grafanaClient.GetDashboardByName(args[0]) + if err != nil { + return err + } + + if delDashboard.UID == nil { + return errors.New("contact point not found") + } + + _, errDelete := grafanaClient.DeleteDashboardByUID(*delDashboard.UID) + if errDelete != nil { + return errDelete + } + + return nil + }, +} diff --git a/observability-lib/cmd/api/notification_policy/delete.go b/observability-lib/cmd/api/notification_policy/delete.go new file mode 100644 index 000000000..918a1d5dd --- /dev/null +++ b/observability-lib/cmd/api/notification_policy/delete.go @@ -0,0 +1,61 @@ +package notification_policy + +import ( + "errors" + "strings" + + "github.com/grafana/grafana-foundation-sdk/go/alerting" + "github.com/smartcontractkit/chainlink-common/observability-lib/api" + "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete [receiver]", + Short: "Delete notification policy", + RunE: func(cmd *cobra.Command, args []string) error { + grafanaClient := api.NewClient( + cmd.Flag("grafana-url").Value.String(), + cmd.Flag("grafana-token").Value.String(), + ) + + if len(args) != 1 { + return errors.New("receiver argument missing") + } + + matchers, err := cmd.Flags().GetStringArray("matchers") + if err != nil { + return err + } + if matchers != nil && len(matchers) > 0 { + objectMatchers := alerting.ObjectMatchers{} + notificationPolicy := alerting.NotificationPolicy{ + Receiver: grafana.Pointer(args[0]), + } + for _, matcher := range matchers { + objectMatcher := strings.Split(matcher, ",") + if len(objectMatcher) != 3 { + return errors.New("invalid matcher format must be key,operator,value") + } + + objectMatchers = append(objectMatchers, objectMatcher) + } + notificationPolicy.ObjectMatchers = &objectMatchers + errDelete := grafanaClient.DeleteNestedPolicy(notificationPolicy) + + if errDelete != nil { + return errDelete + } + } + + return nil + }, +} + +func init() { + deleteCmd.Flags().StringArray("matchers", []string{}, "Object matchers, in the form of key,operator,value e.g. 'key,=,value'") + errMatchers := deleteCmd.MarkFlagRequired("matchers") + if errMatchers != nil { + panic(errMatchers) + } +} diff --git a/observability-lib/cmd/api/notification_policy/list.go b/observability-lib/cmd/api/notification_policy/list.go new file mode 100644 index 000000000..d20971561 --- /dev/null +++ b/observability-lib/cmd/api/notification_policy/list.go @@ -0,0 +1,26 @@ +package notification_policy + +import ( + "github.com/grafana/grafana-foundation-sdk/go/alerting" + "github.com/smartcontractkit/chainlink-common/observability-lib/api" + "github.com/spf13/cobra" +) + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List notification policy", + RunE: func(cmd *cobra.Command, args []string) error { + grafanaClient := api.NewClient( + cmd.Flag("grafana-url").Value.String(), + cmd.Flag("grafana-token").Value.String(), + ) + + notificationPolicyTree, _, err := grafanaClient.GetNotificationPolicy() + if err != nil { + return err + } + + api.PrintPolicyTree(alerting.NotificationPolicy(notificationPolicyTree), 0) + return nil + }, +} diff --git a/observability-lib/cmd/api/notification_policy/notification-policy.go b/observability-lib/cmd/api/notification_policy/notification-policy.go new file mode 100644 index 000000000..8361c3a2a --- /dev/null +++ b/observability-lib/cmd/api/notification_policy/notification-policy.go @@ -0,0 +1,14 @@ +package notification_policy + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "notification-policy [actions]", + Short: "Perform actions on notification policy", +} + +func init() { + Cmd.AddCommand(listCmd, deleteCmd) +} diff --git a/observability-lib/cmd/builder.go b/observability-lib/cmd/builder.go deleted file mode 100644 index 4be5289e2..000000000 --- a/observability-lib/cmd/builder.go +++ /dev/null @@ -1,115 +0,0 @@ -package cmd - -import ( - "errors" - - atlasdon "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/atlas-don" - "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/capabilities" - corenode "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/core-node" - corenodecomponents "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/core-node-components" - k8sresources "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/k8s-resources" - nopocr "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/nop-ocr" - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type TypeDashboard string - -const ( - TypeDashboardCoreNode TypeDashboard = "core-node" - TypeDashboardCoreNodeComponents TypeDashboard = "core-node-components" - TypeDashboardCoreNodeResources TypeDashboard = "core-node-resources" - TypeDashboardDONOCR TypeDashboard = "don-ocr" - TypeDashboardDONOCR2 TypeDashboard = "don-ocr2" - TypeDashboardDONOCR3 TypeDashboard = "don-ocr3" - TypeDashboardNOPOCR2 TypeDashboard = "nop-ocr2" - TypeDashboardNOPOCR3 TypeDashboard = "nop-ocr3" - TypeDashboardCapabilities TypeDashboard = "capabilities" -) - -type OCRVersion string - -const ( - OCRVersionOCR OCRVersion = "ocr" - OCRVersionOCR2 OCRVersion = "ocr2" - OCRVersionOCR3 OCRVersion = "ocr3" -) - -type BuildOptions struct { - Name string - Platform grafana.TypePlatform - TypeDashboard TypeDashboard - MetricsDataSource *grafana.DataSource - LogsDataSource *grafana.DataSource - SlackChannel string - SlackWebhookURL string - AlertsTags map[string]string - AlertsFilters string -} - -func BuildDashboardWithType(options *BuildOptions) (*grafana.Observability, error) { - switch options.TypeDashboard { - case TypeDashboardCoreNode: - return corenode.NewDashboard(&corenode.Props{ - Name: options.Name, - Platform: options.Platform, - MetricsDataSource: options.MetricsDataSource, - LogsDataSource: options.LogsDataSource, - SlackChannel: options.SlackChannel, - SlackWebhookURL: options.SlackWebhookURL, - AlertsTags: options.AlertsTags, - AlertsFilters: options.AlertsFilters, - }) - case TypeDashboardCoreNodeComponents: - return corenodecomponents.NewDashboard(&corenodecomponents.Props{ - Name: options.Name, - Platform: options.Platform, - MetricsDataSource: options.MetricsDataSource, - LogsDataSource: options.LogsDataSource, - }) - case TypeDashboardCoreNodeResources: - if options.Platform != grafana.TypePlatformKubernetes { - return nil, errors.New("core-node-resources dashboard is only available for kubernetes") - } - return k8sresources.NewDashboard(&k8sresources.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - }) - case TypeDashboardDONOCR: - return atlasdon.NewDashboard(&atlasdon.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - OCRVersion: string(OCRVersionOCR), - }) - case TypeDashboardDONOCR2: - return atlasdon.NewDashboard(&atlasdon.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - OCRVersion: string(OCRVersionOCR2), - }) - case TypeDashboardDONOCR3: - return atlasdon.NewDashboard(&atlasdon.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - OCRVersion: string(OCRVersionOCR3), - }) - case TypeDashboardNOPOCR2: - return nopocr.NewDashboard(&nopocr.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - OCRVersion: string(OCRVersionOCR2), - }) - case TypeDashboardNOPOCR3: - return nopocr.NewDashboard(&nopocr.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - OCRVersion: string(OCRVersionOCR3), - }) - case TypeDashboardCapabilities: - return capabilities.NewDashboard(&capabilities.Props{ - Name: options.Name, - MetricsDataSource: options.MetricsDataSource, - }) - default: - return nil, errors.New("invalid dashboard type") - } -} diff --git a/observability-lib/cmd/delete.go b/observability-lib/cmd/delete.go deleted file mode 100644 index f60783c5e..000000000 --- a/observability-lib/cmd/delete.go +++ /dev/null @@ -1,36 +0,0 @@ -package cmd - -import ( - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - "github.com/spf13/cobra" -) - -var DeleteCmd = &cobra.Command{ - Use: "delete", - Short: "Delete Grafana Dashboard", - RunE: func(cmd *cobra.Command, args []string) error { - return grafana.DeleteDashboard(&grafana.DeleteOptions{ - GrafanaURL: cmd.Flag("grafana-url").Value.String(), - GrafanaToken: cmd.Flag("grafana-token").Value.String(), - Name: cmd.Flag("dashboard-name").Value.String(), - }) - }, -} - -func init() { - DeleteCmd.Flags().String("dashboard-name", "", "Name of the dashboard to deploy") - errName := DeleteCmd.MarkFlagRequired("dashboard-name") - if errName != nil { - panic(errName) - } - DeleteCmd.Flags().String("grafana-url", "", "Grafana URL") - errURL := DeleteCmd.MarkFlagRequired("grafana-url") - if errURL != nil { - panic(errURL) - } - DeleteCmd.Flags().String("grafana-token", "", "Grafana API token") - errToken := DeleteCmd.MarkFlagRequired("grafana-token") - if errToken != nil { - panic(errToken) - } -} diff --git a/observability-lib/cmd/deploy.go b/observability-lib/cmd/deploy.go deleted file mode 100644 index 17e2b0633..000000000 --- a/observability-lib/cmd/deploy.go +++ /dev/null @@ -1,109 +0,0 @@ -package cmd - -import ( - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - "github.com/spf13/cobra" -) - -var DeployCmd = &cobra.Command{ - Use: "deploy", - Short: "Deploy Grafana dashboard and associated alerts", - RunE: func(cmd *cobra.Command, args []string) error { - alertsTags, errAlertsTags := cmd.Flags().GetStringToString("alerts-tags") - if errAlertsTags != nil { - return errAlertsTags - } - - var metricsDataSource *grafana.DataSource - if cmd.Flag("metrics-datasource").Value.String() != "" { - var errMetricsDataSource error - metricsDataSource, errMetricsDataSource = grafana.GetDataSourceFromGrafana( - cmd.Flag("metrics-datasource").Value.String(), - cmd.Flag("grafana-url").Value.String(), - cmd.Flag("grafana-token").Value.String(), - ) - - if errMetricsDataSource != nil { - return errMetricsDataSource - } - } - - var logsDataSource *grafana.DataSource - if cmd.Flag("logs-datasource").Value.String() != "" { - var errLogsDataSource error - logsDataSource, errLogsDataSource = grafana.GetDataSourceFromGrafana( - cmd.Flag("logs-datasource").Value.String(), - cmd.Flag("grafana-url").Value.String(), - cmd.Flag("grafana-token").Value.String(), - ) - - if errLogsDataSource != nil { - return errLogsDataSource - } - } - - dashboard, err := BuildDashboardWithType(&BuildOptions{ - Name: cmd.Flag("dashboard-name").Value.String(), - Platform: grafana.TypePlatform(cmd.Flag("platform").Value.String()), - TypeDashboard: TypeDashboard(cmd.Flag("type").Value.String()), - MetricsDataSource: metricsDataSource, - LogsDataSource: logsDataSource, - SlackChannel: cmd.Flag("slack-channel").Value.String(), - SlackWebhookURL: cmd.Flag("slack-webhook").Value.String(), - AlertsTags: alertsTags, - AlertsFilters: cmd.Flag("alerts-filters").Value.String(), - }) - if err != nil { - return err - } - - errDeploy := dashboard.DeployToGrafana(&grafana.DeployOptions{ - GrafanaURL: cmd.Flag("grafana-url").Value.String(), - GrafanaToken: cmd.Flag("grafana-token").Value.String(), - FolderName: cmd.Flag("dashboard-folder").Value.String(), - EnableAlerts: cmd.Flag("enable-alerts").Value.String() == "true", - NotificationTemplates: cmd.Flag("notification-templates").Value.String(), - }) - if errDeploy != nil { - return errDeploy - } - - return nil - }, -} - -func init() { - DeployCmd.Flags().String("dashboard-name", "", "Name of the dashboard to deploy") - errName := DeployCmd.MarkFlagRequired("dashboard-name") - if errName != nil { - panic(errName) - } - DeployCmd.Flags().String("dashboard-folder", "", "Dashboard folder") - errFolder := DeployCmd.MarkFlagRequired("dashboard-folder") - if errFolder != nil { - panic(errFolder) - } - DeployCmd.Flags().String("grafana-url", "", "Grafana URL") - errURL := DeployCmd.MarkFlagRequired("grafana-url") - if errURL != nil { - panic(errURL) - } - DeployCmd.Flags().String("grafana-token", "", "Grafana API token") - errToken := DeployCmd.MarkFlagRequired("grafana-token") - if errToken != nil { - panic(errToken) - } - DeployCmd.Flags().String("metrics-datasource", "Prometheus", "Metrics datasource name") - DeployCmd.Flags().String("logs-datasource", "", "Logs datasource name") - DeployCmd.Flags().String("platform", "docker", "Platform where the dashboard is deployed (docker or kubernetes)") - DeployCmd.Flags().String("type", "core-node", "Dashboard type can be either core-node | core-node-components | core-node-resources | don-ocr | don-ocr2 | don-ocr3 | nop-ocr2 | nop-ocr3") - DeployCmd.Flags().Bool("enable-alerts", false, "Deploy alerts") - DeployCmd.Flags().StringToString("alerts-tags", map[string]string{ - "team": "chainlink-team", - }, "Alerts tags") - DeployCmd.Flags().String("notification-templates", "", "Filepath in yaml format, will create notification templates depending on key-value pairs in the yaml file") - DeployCmd.Flags().String("slack-channel", "", "Slack channel, required when setting up slack contact points") - DeployCmd.Flags().String("slack-webhook", "", "Slack webhook URL, required when setting up slack contact points") - DeployCmd.Flags().String("slack-token", "", "Slack token, required when setting up slack contact points and slack webhook is not provided") - DeployCmd.Flags().String("alerts-filters", "", "Alerts Filters applied to the queries") -} diff --git a/observability-lib/cmd/generate.go b/observability-lib/cmd/generate.go deleted file mode 100644 index 821c3ee90..000000000 --- a/observability-lib/cmd/generate.go +++ /dev/null @@ -1,46 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - "github.com/spf13/cobra" -) - -var GenerateCmd = &cobra.Command{ - Use: "generate", - Short: "Generate Grafana Dashboard JSON", - RunE: func(cmd *cobra.Command, args []string) error { - dashboard, err := BuildDashboardWithType(&BuildOptions{ - Name: cmd.Flag("dashboard-name").Value.String(), - Platform: grafana.TypePlatform(cmd.Flag("platform").Value.String()), - TypeDashboard: TypeDashboard(cmd.Flag("type").Value.String()), - MetricsDataSource: grafana.NewDataSource(cmd.Flag("metrics-datasource").Value.String(), ""), - LogsDataSource: grafana.NewDataSource(cmd.Flag("logs-datasource").Value.String(), ""), - }) - if err != nil { - return err - } - - dashboardJSON, errDashboardJSON := dashboard.GenerateJSON() - if errDashboardJSON != nil { - return errDashboardJSON - } - - fmt.Print(string(dashboardJSON)) - - return nil - }, -} - -func init() { - GenerateCmd.Flags().String("dashboard-name", "", "Name of the dashboard to deploy") - errName := GenerateCmd.MarkFlagRequired("dashboard-name") - if errName != nil { - panic(errName) - } - GenerateCmd.Flags().String("metrics-datasource", "Prometheus", "Metrics datasource name") - GenerateCmd.Flags().String("logs-datasource", "", "Logs datasource name") - GenerateCmd.Flags().String("platform", "docker", "Platform where the dashboard is deployed (docker or kubernetes)") - GenerateCmd.Flags().String("type", "core-node", "Dashboard type can be either core-node | core-node-components | core-node-resources | don-ocr | don-ocr2 | don-ocr3") -} diff --git a/observability-lib/cmd/log.go b/observability-lib/cmd/log.go deleted file mode 100644 index 8e643f1f9..000000000 --- a/observability-lib/cmd/log.go +++ /dev/null @@ -1,28 +0,0 @@ -package cmd - -import ( - "os" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" -) - -const ( - LogLevelEnvVar = "DASHBOARD_LOG_LEVEL" -) - -var ( - Logger zerolog.Logger -) - -func init() { - lvlStr := os.Getenv(LogLevelEnvVar) - if lvlStr == "" { - lvlStr = "info" - } - lvl, err := zerolog.ParseLevel(lvlStr) - if err != nil { - panic(err) - } - Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).Level(lvl) -} diff --git a/observability-lib/cmd/notification-templates.yaml b/observability-lib/cmd/notification-templates.yaml deleted file mode 100644 index 60df98cc6..000000000 --- a/observability-lib/cmd/notification-templates.yaml +++ /dev/null @@ -1,65 +0,0 @@ -slack: |- - {{ define "slack.chainlink.text" }} - {{- $root := . -}} - {{ range .Alerts }} - {{ template "slack.print_alert" . }} - {{ end }} - {{ end }} - - {{ define "slack.print_alert" }} - *Summary:* ```{{ .Annotations.summary }}``` - {{ if gt (len .Annotations.description) 0 }}*Description:* ```{{ .Annotations.description }}```{{ end }} - *Labels:* ```{{- range .Labels.SortedPairs }} - {{- if and (ne .Name "alertname") (ne .Name "grafana_folder") (ne .Name "severity") }} - • {{ .Name }}: {{ .Value }} - {{- end }} - {{- end }}``` - {{- if gt (len .GeneratorURL ) 0 }} - <{{ .GeneratorURL }}|:grafana: Grafana Alert URL> - {{- end }} - {{- if gt (len .DashboardURL ) 0 }} - <{{ .DashboardURL }}|:desktop_computer: Dashboard URL> - {{- end }} - {{- if gt (len .PanelURL ) 0 }} - <{{ .PanelURL }}|:bar_chart: Panel URL> - {{- end }} - {{- if gt (len .SilenceURL ) 0 }} - <{{ .SilenceURL }}|:no_bell: Silence alert> - {{- end }} - {{- if gt (len .Annotations.runbook_url ) 0 }} - <{{ .Annotations.runbook_url }}|:spiral_note_pad: Runbook> - {{- end }} - {{ end }} - - {{ define "slack.chainlink.color" }} - {{- if ne .Status "firing" -}} - good - {{- else if eq .CommonLabels.severity "critical" -}} - danger - {{- else if eq .CommonLabels.severity "warning" -}} - warning - {{- end -}} - {{ end }} - - {{ define "alert_severity_prefix_emoji" -}} - {{- if ne .Status "firing" -}} - :white_check_mark: - {{- else if eq .CommonLabels.severity "critical" -}} - :red_circle: - {{- else if eq .CommonLabels.severity "warning" -}} - :warning: - {{- end -}} - {{- end -}} - - {{ define "slack.chainlink.title" }} - {{ template "alert_severity_prefix_emoji" . }} [{{- if gt (len .Alerts.Resolved) 0}}{{ .Status | toUpper }}{{- else }}{{ .CommonLabels.severity | toUpper }}{{- end }}:{{ .Alerts | len }}] {{ .CommonLabels.alertname }} - {{ end }} - -pagerduty: |- - {{ define "pagerduty.chainlink.title" }} - [{{- if gt (len .Alerts.Resolved) 0}}{{ .Status | toUpper }}{{- else }}{{ .CommonLabels.severity | toUpper }}{{- end }}:{{ .Alerts | len }}] {{ .CommonLabels.alertname }} - {{ end }} - - {{ define "pagerduty.chainlink.severity" }} - {{ if .CommonLabels.severity }}{{ .CommonLabels.severity | toLower }}{{ else }}critical{{ end }} - {{ end }} \ No newline at end of file diff --git a/observability-lib/cmd/root.go b/observability-lib/cmd/root.go new file mode 100644 index 000000000..df7e375f2 --- /dev/null +++ b/observability-lib/cmd/root.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "log" + + "github.com/smartcontractkit/chainlink-common/observability-lib/cmd/api" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "observability-lib [command]", + Short: "observability-lib CLI to perform actions on observability resources", +} + +func init() { + rootCmd.AddCommand(api.Cmd) +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + log.Fatalln(err) + } +} diff --git a/observability-lib/dashboards/atlas-don/component.go b/observability-lib/dashboards/atlas-don/component.go deleted file mode 100644 index 098bda871..000000000 --- a/observability-lib/dashboards/atlas-don/component.go +++ /dev/null @@ -1,790 +0,0 @@ -package atlasdon - -import ( - "fmt" - - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/common" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - if props.OCRVersion == "" { - return nil, fmt.Errorf("OCRVersion is required") - } - - if props.MetricsDataSource == nil { - return nil, fmt.Errorf("MetricsDataSource is required") - } else { - if props.MetricsDataSource.Name == "" { - return nil, fmt.Errorf("MetricsDataSource.Name is required") - } - if props.MetricsDataSource.UID == "" { - return nil, fmt.Errorf("MetricsDataSource.UID is required") - } - } - - props.platformOpts = platformPanelOpts(props.OCRVersion) - if props.Tested { - props.platformOpts.LabelQuery = "" - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"DON", props.OCRVersion}, - Refresh: "30s", - TimeFrom: "now-30m", - TimeTo: "now", - }) - - builder.AddVars(vars(props)...) - - builder.AddRow("Summary") - builder.AddPanel(summary(props)...) - - builder.AddRow("OCR Contract Oracle") - builder.AddPanel(ocrContractConfigOracle(props)...) - - builder.AddRow("DON Nodes") - builder.AddPanel(ocrContractConfigNodes(props)...) - - builder.AddRow("Price Reporting") - builder.AddPanel(priceReporting(props)...) - - builder.AddRow("Round / Epoch Progression") - builder.AddPanel(roundEpochProgression(props)...) - - builder.AddRow("OCR Contract Config Delta") - builder.AddPanel(ocrContractConfigDelta(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Job", - Name: "job", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{namespace` + p.platformOpts.LabelFilters["namespace"] + `}, job)`, - })) - - variableFeedID := "feed_id" - if p.OCRVersion == "ocr3" { - variableFeedID = "feed_id_name" - } - - variableQueryContract := grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Contract", - Name: "contract", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(` + p.OCRVersion + `_contract_config_f{job="$job"}, contract)`, - }) - - variableQueryFeedID := grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Feed ID", - Name: variableFeedID, - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(` + p.OCRVersion + `_contract_config_f{job="$job", contract="$contract"}, ` + variableFeedID + `)`, - Multi: true, - }) - - variables = append(variables, variableQueryContract) - - switch p.OCRVersion { - case "ocr2": - variables = append(variables, variableQueryFeedID) - case "ocr3": - variables = append(variables, variableQueryFeedID) - } - - return variables -} - -func summary(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Telemetry Down", - Description: "Which jobs are not receiving any telemetry?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_telemetry_down{` + p.platformOpts.LabelQuery + `} == 1`, - Legend: "{{job}} | {{report_type}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Oracle Down", - Description: "Which NOPs are not providing any telemetry?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_oracle_telemetry_down_except_telemetry_down{job=~"${job}", oracle!="csa_unknown"} == 1`, - Legend: "{{oracle}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Feeds reporting failure", - Description: "Which feeds are failing to report?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_feed_reporting_failure_except_feed_telemetry_down{job=~"${job}", oracle!="csa_unknown"} == 1`, - Legend: "{{feed_id_name}} on {{job}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Feed telemetry Down", - Description: "Which feeds are not receiving any telemetry?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_feed_telemetry_down_except_telemetry_down{job=~"${job}"} == 1`, - Legend: "{{feed_id_name}} on {{job}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Oracles no observations", - Description: "Which NOPs are not providing observations?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_oracle_blind_except_telemetry_down{job=~"${job}"} == 1`, - Legend: "{{oracle}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Oracles not contributing observations to feeds", - Description: "Which oracles are failing to make observations on feeds they should be participating in?", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `bool:` + p.OCRVersion + `_oracle_feed_no_observations_except_oracle_blind_except_feed_reporting_failure_except_feed_telemetry_down{job=~"${job}"} == 1`, - Legend: "{{oracle}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "green"}, - {Value: grafana.Pointer[float64](0.99), Color: "red"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - return panels -} - -func ocrContractConfigOracle(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "OCR Contract Oracle Active", - Description: "set to one as long as an oracle is on a feed", - Span: 24, - Height: 8, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(` + p.OCRVersion + `_contract_oracle_active{` + p.platformOpts.LabelQuery + `}) by (contract, oracle)`, - Legend: "{{oracle}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - return panels -} - -func ocrContractConfigNodes(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - var variableFeedID string - switch p.OCRVersion { - case "ocr": - variableFeedID = "contract" - case "ocr2": - variableFeedID = "feed_id" - case "ocr3": - variableFeedID = "feed_id_name" - } - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Number of NOPs", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_n{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + variableFeedID + `}}`, - }, - { - Expr: `` + p.OCRVersion + `_contract_config_r_max{` + p.platformOpts.LabelQuery + `}`, - Legend: `Max nodes`, - }, - { - Expr: `avg(2 * ` + p.OCRVersion + `_contract_config_f{` + p.platformOpts.LabelQuery + `} + 1)`, - Legend: `Min nodes`, - }, - }, - Min: grafana.Pointer[float64](0), - }, - })) - - return panels -} - -func priceReporting(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - telemetryP2PReceivedTotal := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "P2P messages received", - Description: "From an individual node's perspective, how many messages are they receiving from other nodes? Uses ocr_telemetry_p2p_received_total", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum by (sender, receiver) (increase(` + p.OCRVersion + `_telemetry_p2p_received_total{job=~"${job}"}[5m]))`, - Legend: `{{sender}} > {{receiver}}`, - }, - }, - }, - }) - - telemetryP2PReceivedTotalRate := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "P2P messages received Rate", - Description: "From an individual node's perspective, how many messages are they receiving from other nodes? Uses ocr_telemetry_p2p_received_total", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum by (sender, receiver) (rate(` + p.OCRVersion + `_telemetry_p2p_received_total{job=~"${job}"}[5m]))`, - Legend: `{{sender}} > {{receiver}}`, - }, - }, - }, - }) - - telemetryObservationAsk := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Ask observation in MessageObserve sent", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_observation_ask{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryObservation := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Price observation in MessageObserve sent", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_observation{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryObservationBid := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Bid observation in MessageObserve sent", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_observation_bid{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryMessageProposeObservationAsk := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Ask MessagePropose observations", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_message_propose_observation_ask{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryMessageProposeObservation := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Price MessagePropose observations", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_message_propose_observation{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryMessageProposeObservationBid := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Bid MessagePropose observations", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_message_propose_observation_bid{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryMessageProposeObservationTotal := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Total number of observations included in MessagePropose", - Description: "How often is a node's observation included in the report?", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_message_propose_observation_total{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - telemetryMessageObserveTotal := grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Total MessageObserve sent", - Description: "From an individual node's perspective, how often are they sending an observation?", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `rate(` + p.OCRVersion + `_telemetry_message_observe_total{` + p.platformOpts.LabelQuery + `}[5m])`, - Legend: `{{oracle}}`, - }, - }, - }, - }) - - switch p.OCRVersion { - case "ocr": - panels = append(panels, telemetryP2PReceivedTotal) - panels = append(panels, telemetryP2PReceivedTotalRate) - panels = append(panels, telemetryObservation) - panels = append(panels, telemetryMessageObserveTotal) - case "ocr2": - panels = append(panels, telemetryP2PReceivedTotal) - panels = append(panels, telemetryP2PReceivedTotalRate) - panels = append(panels, telemetryObservation) - panels = append(panels, telemetryMessageObserveTotal) - case "ocr3": - panels = append(panels, telemetryP2PReceivedTotal) - panels = append(panels, telemetryP2PReceivedTotalRate) - panels = append(panels, telemetryObservationAsk) - panels = append(panels, telemetryObservation) - panels = append(panels, telemetryObservationBid) - panels = append(panels, telemetryMessageProposeObservationAsk) - panels = append(panels, telemetryMessageProposeObservation) - panels = append(panels, telemetryMessageProposeObservationBid) - panels = append(panels, telemetryMessageProposeObservationTotal) - panels = append(panels, telemetryMessageObserveTotal) - } - - return panels -} - -func roundEpochProgression(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - var variableFeedID string - switch p.OCRVersion { - case "ocr": - variableFeedID = "contract" - case "ocr2": - variableFeedID = "feed_id" - case "ocr3": - variableFeedID = "feed_id_name" - } - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Agreed Epoch Progression", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_feed_agreed_epoch{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + variableFeedID + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Round Epoch Progression", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_telemetry_epoch_round{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{oracle}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Rounds Started", - Description: `Tracks individual nodes firing "new round" message via telemetry (not part of P2P messages)`, - Span: 12, - Height: 6, - Decimals: 1, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `rate(` + p.OCRVersion + `_telemetry_round_started_total{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{oracle}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Telemetry Ingested", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `rate(` + p.OCRVersion + `_telemetry_ingested_total{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{oracle}}`, - }, - }, - }, - })) - - return panels -} - -func ocrContractConfigDelta(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Relative Deviation Threshold", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_alpha{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Max Contract Value Age Seconds", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_c_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Observation Grace Period Seconds", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_grace_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Bad Epoch Timeout Seconds", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_progress_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Resend Interval Seconds", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_resend_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Round Interval Seconds", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_round_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Transmission Stage Timeout Second", - Span: 8, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `` + p.OCRVersion + `_contract_config_delta_stage_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{contract}}", - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - return panels -} diff --git a/observability-lib/dashboards/atlas-don/component_test.go b/observability-lib/dashboards/atlas-don/component_test.go deleted file mode 100644 index 7ce5bb775..000000000 --- a/observability-lib/dashboards/atlas-don/component_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package atlasdon_test - -import ( - "flag" - "os" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - atlasdon "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/atlas-don" -) - -var update = flag.Bool("update", false, "update golden test files") - -const fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := atlasdon.NewDashboard(&atlasdon.Props{ - Name: "DON OCR Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", "1"), - OCRVersion: "ocr2", - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := atlasdon.NewDashboard(&atlasdon.Props{ - Name: "DON OCR Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", "1"), - OCRVersion: "ocr2", - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "DON OCR Dashboard", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/atlas-don/platform.go b/observability-lib/dashboards/atlas-don/platform.go deleted file mode 100644 index dd953a2f7..000000000 --- a/observability-lib/dashboards/atlas-don/platform.go +++ /dev/null @@ -1,57 +0,0 @@ -package atlasdon - -import ( - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type platformOpts struct { - LabelFilters map[string]string - LabelFilter string - LegendString string - LabelQuery string -} - -type Props struct { - Name string // Name is the name of the dashboard - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics - OCRVersion string // OCRVersion is the version of the OCR (ocr, ocr2, ocr3) - platformOpts platformOpts - Tested bool -} - -// PlatformPanelOpts generate different queries depending on params -func platformPanelOpts(ocrVersion string) platformOpts { - po := platformOpts{ - LabelFilters: map[string]string{ - "contract": `=~"${contract}"`, - }, - } - - variableFeedID := "feed_id" - if ocrVersion == "ocr3" { - variableFeedID = "feed_id_name" - } - - switch ocrVersion { - case "ocr2": - po.LabelFilters[variableFeedID] = `=~"${` + variableFeedID + `}"` - case "ocr3": - po.LabelFilters[variableFeedID] = `=~"${` + variableFeedID + `}"` - } - namespace := "otpe" - if ocrVersion == "ocr2" { - namespace = "otpe2" - } else if ocrVersion == "ocr3" { - namespace = "otpe3" - } - - po.LabelFilters["namespace"] = `="` + namespace + `"` - po.LabelFilters["job"] = `=~"${job}"` - po.LabelFilter = "job" - po.LegendString = "job" - - for key, value := range po.LabelFilters { - po.LabelQuery += key + value + ", " - } - return po -} diff --git a/observability-lib/dashboards/atlas-don/test-output.json b/observability-lib/dashboards/atlas-don/test-output.json deleted file mode 100644 index 65b2a8f14..000000000 --- a/observability-lib/dashboards/atlas-don/test-output.json +++ /dev/null @@ -1,1502 +0,0 @@ -{ - "Dashboard": { - "title": "DON OCR Dashboard", - "tags": [ - "DON", - "ocr2" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-30m", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "row", - "collapsed": false, - "title": "Summary", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 1, - "targets": [ - { - "expr": "bool:ocr2_telemetry_down{} == 1", - "format": "", - "legendFormat": "{{job}} | {{report_type}}", - "refId": "" - } - ], - "title": "Telemetry Down", - "description": "Which jobs are not receiving any telemetry?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 2, - "targets": [ - { - "expr": "bool:ocr2_oracle_telemetry_down_except_telemetry_down{job=~\"${job}\", oracle!=\"csa_unknown\"} == 1", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Oracle Down", - "description": "Which NOPs are not providing any telemetry?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 8, - "y": 1 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 3, - "targets": [ - { - "expr": "bool:ocr2_feed_reporting_failure_except_feed_telemetry_down{job=~\"${job}\", oracle!=\"csa_unknown\"} == 1", - "format": "", - "legendFormat": "{{feed_id_name}} on {{job}}", - "refId": "" - } - ], - "title": "Feeds reporting failure", - "description": "Which feeds are failing to report?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 16, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 4, - "targets": [ - { - "expr": "bool:ocr2_feed_telemetry_down_except_telemetry_down{job=~\"${job}\"} == 1", - "format": "", - "legendFormat": "{{feed_id_name}} on {{job}}", - "refId": "" - } - ], - "title": "Feed telemetry Down", - "description": "Which feeds are not receiving any telemetry?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 5 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 5, - "targets": [ - { - "expr": "bool:ocr2_oracle_blind_except_telemetry_down{job=~\"${job}\"} == 1", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Oracles no observations", - "description": "Which NOPs are not providing observations?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 8, - "y": 5 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 6, - "targets": [ - { - "expr": "bool:ocr2_oracle_feed_no_observations_except_oracle_blind_except_feed_reporting_failure_except_feed_telemetry_down{job=~\"${job}\"} == 1", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Oracles not contributing observations to feeds", - "description": "Which oracles are failing to make observations on feeds they should be participating in?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 16, - "y": 5 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "green" - }, - { - "value": 0.99, - "color": "red" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "OCR Contract Oracle", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 9 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 7, - "targets": [ - { - "expr": "sum(ocr2_contract_oracle_active{}) by (contract, oracle)", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "OCR Contract Oracle Active", - "description": "set to one as long as an oracle is on a feed", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 10 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "DON Nodes", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 18 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 8, - "targets": [ - { - "expr": "ocr2_contract_config_n{}", - "format": "", - "legendFormat": "{{feed_id}}", - "refId": "" - }, - { - "expr": "ocr2_contract_config_r_max{}", - "format": "", - "legendFormat": "Max nodes", - "refId": "" - }, - { - "expr": "avg(2 * ocr2_contract_config_f{} + 1)", - "format": "", - "legendFormat": "Min nodes", - "refId": "" - } - ], - "title": "Number of NOPs", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 19 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "min": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Price Reporting", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 25 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 9, - "targets": [ - { - "expr": "sum by (sender, receiver) (increase(ocr2_telemetry_p2p_received_total{job=~\"${job}\"}[5m]))", - "format": "", - "legendFormat": "{{sender}} \u003e {{receiver}}", - "refId": "" - } - ], - "title": "P2P messages received", - "description": "From an individual node's perspective, how many messages are they receiving from other nodes? Uses ocr_telemetry_p2p_received_total", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 26 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 10, - "targets": [ - { - "expr": "sum by (sender, receiver) (rate(ocr2_telemetry_p2p_received_total{job=~\"${job}\"}[5m]))", - "format": "", - "legendFormat": "{{sender}} \u003e {{receiver}}", - "refId": "" - } - ], - "title": "P2P messages received Rate", - "description": "From an individual node's perspective, how many messages are they receiving from other nodes? Uses ocr_telemetry_p2p_received_total", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 32 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 11, - "targets": [ - { - "expr": "ocr2_telemetry_observation{}", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Price observation in MessageObserve sent", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 38 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 12, - "targets": [ - { - "expr": "rate(ocr2_telemetry_message_observe_total{}[5m])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Total MessageObserve sent", - "description": "From an individual node's perspective, how often are they sending an observation?", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 44 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Round / Epoch Progression", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 50 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 13, - "targets": [ - { - "expr": "ocr2_telemetry_feed_agreed_epoch{}", - "format": "", - "legendFormat": "{{feed_id}}", - "refId": "" - } - ], - "title": "Agreed Epoch Progression", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 51 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 14, - "targets": [ - { - "expr": "ocr2_telemetry_epoch_round{}", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Round Epoch Progression", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 51 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 15, - "targets": [ - { - "expr": "rate(ocr2_telemetry_round_started_total{}[1m])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Rounds Started", - "description": "Tracks individual nodes firing \"new round\" message via telemetry (not part of P2P messages)", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 57 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 16, - "targets": [ - { - "expr": "rate(ocr2_telemetry_ingested_total{}[1m])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Telemetry Ingested", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 57 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "OCR Contract Config Delta", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 63 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 17, - "targets": [ - { - "expr": "ocr2_contract_config_alpha{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Relative Deviation Threshold", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 64 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 18, - "targets": [ - { - "expr": "ocr2_contract_config_delta_c_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Max Contract Value Age Seconds", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 8, - "y": 64 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 19, - "targets": [ - { - "expr": "ocr2_contract_config_delta_grace_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Observation Grace Period Seconds", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 16, - "y": 64 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 20, - "targets": [ - { - "expr": "ocr2_contract_config_delta_progress_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Bad Epoch Timeout Seconds", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 68 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 21, - "targets": [ - { - "expr": "ocr2_contract_config_delta_resend_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Resend Interval Seconds", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 8, - "y": 68 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 22, - "targets": [ - { - "expr": "ocr2_contract_config_delta_round_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Round Interval Seconds", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 16, - "y": 68 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 23, - "targets": [ - { - "expr": "ocr2_contract_config_delta_stage_seconds{}", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Transmission Stage Timeout Second", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 72 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "query", - "name": "job", - "label": "Job", - "description": "", - "query": "label_values(up{namespace=\"otpe2\"}, job)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "contract", - "label": "Contract", - "description": "", - "query": "label_values(ocr2_contract_config_f{job=\"$job\"}, contract)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "feed_id", - "label": "Feed ID", - "description": "", - "query": "label_values(ocr2_contract_config_f{job=\"$job\", contract=\"$contract\"}, feed_id)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": true, - "sort": 1 - } - ] - }, - "annotations": {} - }, - "Alerts": null, - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/dashboards/capabilities/component.go b/observability-lib/dashboards/capabilities/component.go deleted file mode 100644 index 9c36d9be7..000000000 --- a/observability-lib/dashboards/capabilities/component.go +++ /dev/null @@ -1,219 +0,0 @@ -package capabilities - -import ( - "fmt" - - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type Props struct { - Name string // Name is the name of the dashboard - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics -} - -// NewDashboard creates a Capabilities dashboard -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - if props.MetricsDataSource == nil { - return nil, fmt.Errorf("MetricsDataSource is required") - } else { - if props.MetricsDataSource.Name == "" { - return nil, fmt.Errorf("MetricsDataSource.Name is required") - } - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"Capabilities"}, - Refresh: "30s", - TimeFrom: "now-7d", - TimeTo: "now", - }) - - builder.AddVars(vars(props)...) - - builder.AddRow("Common indicators for capabilities") - builder.AddPanel(capabilitiesCommon(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Environment", - Name: "env", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up, env)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Cluster", - Name: "cluster", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env"}, cluster)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Namespace", - Name: "namespace", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster"}, namespace)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Job", - Name: "job", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", namespace="$namespace"}, job)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Pod", - Name: "pod", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", namespace="$namespace", job="$job"}, pod)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Capability", - Name: "capability", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", namespace="$namespace", job="$job"}, pod)`, - Multi: false, - })) - - return variables -} - -func capabilitiesCommon(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Execution Time", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_execution_time_ms`, - Legend: "{{capability}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Runs Count", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_runs_count`, - Legend: "{{capability}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Runs Fault Count", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_runs_fault_count`, - Legend: "{{capability}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Runs Invalid Count", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_runs_invalid_count`, - Legend: "{{capability}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Runs Unauthorized Count", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_runs_unauthorized_count`, - Legend: "{{capability}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Runs No Resource Count", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `capability_runs_no_resource_count`, - Legend: "{{capability}}", - }, - }, - }, - })) - - return panels -} diff --git a/observability-lib/dashboards/capabilities/component_test.go b/observability-lib/dashboards/capabilities/component_test.go deleted file mode 100644 index 90ad5ce9e..000000000 --- a/observability-lib/dashboards/capabilities/component_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package capabilities_test - -import ( - "flag" - "os" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/capabilities" -) - -var update = flag.Bool("update", false, "update golden test files") - -const fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := capabilities.NewDashboard(&capabilities.Props{ - Name: "Capabilities Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := capabilities.NewDashboard(&capabilities.Props{ - Name: "Capabilities Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "Capabilities Dashboard", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/capabilities/test-output.json b/observability-lib/dashboards/capabilities/test-output.json deleted file mode 100644 index ff7a21a65..000000000 --- a/observability-lib/dashboards/capabilities/test-output.json +++ /dev/null @@ -1,467 +0,0 @@ -{ - "Dashboard": { - "title": "Capabilities Dashboard", - "tags": [ - "Capabilities" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-7d", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "row", - "collapsed": false, - "title": "Common indicators for capabilities", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 1, - "targets": [ - { - "expr": "capability_execution_time_ms", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Execution Time", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 1 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 2, - "targets": [ - { - "expr": "capability_runs_count", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Runs Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 1 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 3, - "targets": [ - { - "expr": "capability_runs_fault_count", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Runs Fault Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 1 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 4, - "targets": [ - { - "expr": "capability_runs_invalid_count", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Runs Invalid Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 1 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 5, - "targets": [ - { - "expr": "capability_runs_unauthorized_count", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Runs Unauthorized Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 5 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 6, - "targets": [ - { - "expr": "capability_runs_no_resource_count", - "format": "", - "legendFormat": "{{capability}}", - "refId": "" - } - ], - "title": "Runs No Resource Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 5 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "query", - "name": "env", - "label": "Environment", - "description": "", - "query": "label_values(up, env)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "cluster", - "label": "Cluster", - "description": "", - "query": "label_values(up{env=\"$env\"}, cluster)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "namespace", - "label": "Namespace", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\"}, namespace)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "job", - "label": "Job", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", namespace=\"$namespace\"}, job)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "pod", - "label": "Pod", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", namespace=\"$namespace\", job=\"$job\"}, pod)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "capability", - "label": "Capability", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", namespace=\"$namespace\", job=\"$job\"}, pod)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - } - ] - }, - "annotations": {} - }, - "Alerts": null, - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/dashboards/core-node-components/component.go b/observability-lib/dashboards/core-node-components/component.go deleted file mode 100644 index 6175fd438..000000000 --- a/observability-lib/dashboards/core-node-components/component.go +++ /dev/null @@ -1,210 +0,0 @@ -package corenodecomponents - -import ( - "fmt" - - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/common" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - props.platformOpts = platformPanelOpts() - if props.Tested { - props.platformOpts.LabelQuery = "" - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"Core", "Node", "Components"}, - Refresh: "30s", - TimeFrom: "now-30m", - TimeTo: "now", - }) - - builder.AddVars(vars(props)...) - builder.AddPanel(panelsGeneralInfo(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - variables = append(variables, grafana.NewIntervalVariable(&grafana.IntervalVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Interval", - Name: "interval", - }, - Interval: "30s,1m,5m,15m,30m,1h,6h,12h", - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Environment", - Name: "env", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up, env)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Cluster", - Name: "cluster", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env"}, cluster)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Blockchain", - Name: "blockchain", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster"}, blockchain)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Product", - Name: "product", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain"}, product)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Network Type", - Name: "network_type", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", product="$product"}, network_type)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Component", - Name: "component", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", network_type="$network_type"}, component)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Service", - Name: "service", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", blockchain="$blockchain", network_type="$network_type", component="$component"}, service)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Service ID", - Name: "service_id", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(health{cluster="$cluster", blockchain="$blockchain", network_type="$network_type", component="$component", service="$service"}, service_id)`, - Multi: true, - IncludeAll: true, - })) - - return variables -} - -func panelsGeneralInfo(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Components Health Avg by Service", - Span: 24, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * avg(avg_over_time(health{` + p.platformOpts.LabelQuery + `service_id=~"${service_id}"}[$interval])) by (service_id, version, service, cluster, env)`, - Legend: "{{service_id}}", - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - }, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationVertical, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Components Health by Service", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * (health{` + p.platformOpts.LabelQuery + `service_id=~"${service_id}"})`, - Legend: "{{service_id}}", - }, - }, - Min: grafana.Pointer[float64](0), - Max: grafana.Pointer[float64](100), - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Components Health Avg by Service", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * (avg(avg_over_time(health{` + p.platformOpts.LabelQuery + `service_id=~"${service_id}"}[$interval])) by (service_id, version, service, cluster, env))`, - Legend: "{{service_id}}", - }, - }, - Min: grafana.Pointer[float64](0), - Max: grafana.Pointer[float64](100), - }, - })) - - panels = append(panels, grafana.NewLogPanel(&grafana.LogPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.LogsDataSource.Name, - Title: "Logs with severity >= error", - Span: 24, - Height: 6, - Query: []grafana.Query{ - { - Expr: `{env="${env}", cluster="${cluster}", product="${product}", network_type="${network_type}", instance=~"${service}"} | json | level=~"(error|panic|fatal|crit)"`, - Legend: "", - }, - }, - }, - })) - - return panels -} diff --git a/observability-lib/dashboards/core-node-components/component_test.go b/observability-lib/dashboards/core-node-components/component_test.go deleted file mode 100644 index ce257164c..000000000 --- a/observability-lib/dashboards/core-node-components/component_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package corenodecomponents_test - -import ( - "flag" - "os" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - corenodecomponents "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/core-node-components" -) - -var update = flag.Bool("update", false, "update golden test files") - -const fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := corenodecomponents.NewDashboard(&corenodecomponents.Props{ - Name: "Core Node Components Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - LogsDataSource: grafana.NewDataSource("Loki", ""), - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := corenodecomponents.NewDashboard(&corenodecomponents.Props{ - Name: "Core Node Components Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - LogsDataSource: grafana.NewDataSource("Loki", ""), - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "Core Node Components Dashboard", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/core-node-components/platform.go b/observability-lib/dashboards/core-node-components/platform.go deleted file mode 100644 index cd64ad669..000000000 --- a/observability-lib/dashboards/core-node-components/platform.go +++ /dev/null @@ -1,40 +0,0 @@ -package corenodecomponents - -import "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - -type platformOpts struct { - // Platform is infrastructure deployment platform: docker or k8s - Platform string - LabelFilters map[string]string - LabelFilter string - LegendString string - LabelQuery string -} - -type Props struct { - Name string // Name is the name of the dashboard - Platform grafana.TypePlatform // Platform is infrastructure deployment platform: docker or k8s - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics - LogsDataSource *grafana.DataSource // LogsDataSource is the datasource for querying logs - platformOpts platformOpts - Tested bool -} - -// PlatformPanelOpts generate different queries for "docker" and "k8s" deployment platforms -func platformPanelOpts() platformOpts { - po := platformOpts{ - LabelFilters: map[string]string{ - "env": `=~"${env}"`, - "cluster": `=~"${cluster}"`, - "blockchain": `=~"${blockchain}"`, - "product": `=~"${product}"`, - "network_type": `=~"${network_type}"`, - "component": `=~"${component}"`, - "service": `=~"${service}"`, - }, - } - for key, value := range po.LabelFilters { - po.LabelQuery += key + value + ", " - } - return po -} diff --git a/observability-lib/dashboards/core-node-components/test-output.json b/observability-lib/dashboards/core-node-components/test-output.json deleted file mode 100644 index 734c36e22..000000000 --- a/observability-lib/dashboards/core-node-components/test-output.json +++ /dev/null @@ -1,432 +0,0 @@ -{ - "Dashboard": { - "title": "Core Node Components Dashboard", - "tags": [ - "Core", - "Node", - "Components" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-30m", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "stat", - "id": 1, - "targets": [ - { - "expr": "100 * avg(avg_over_time(health{service_id=~\"${service_id}\"}[$interval])) by (service_id, version, service, cluster, env)", - "format": "", - "legendFormat": "{{service_id}}", - "refId": "" - } - ], - "title": "Components Health Avg by Service", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 24, - "x": 0, - "y": 0 - }, - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "vertical" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 80, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 2, - "targets": [ - { - "expr": "100 * (health{service_id=~\"${service_id}\"})", - "format": "", - "legendFormat": "{{service_id}}", - "refId": "" - } - ], - "title": "Components Health by Service", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 4 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "min": 0, - "max": 100, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 3, - "targets": [ - { - "expr": "100 * (avg(avg_over_time(health{service_id=~\"${service_id}\"}[$interval])) by (service_id, version, service, cluster, env))", - "format": "", - "legendFormat": "{{service_id}}", - "refId": "" - } - ], - "title": "Components Health Avg by Service", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 10 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "min": 0, - "max": 100, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "logs", - "id": 4, - "targets": [ - { - "expr": "{env=\"${env}\", cluster=\"${cluster}\", product=\"${product}\", network_type=\"${network_type}\", instance=~\"${service}\"} | json | level=~\"(error|panic|fatal|crit)\"", - "format": "", - "legendFormat": "", - "refId": "" - } - ], - "title": "Logs with severity \u003e= error", - "description": "", - "transparent": false, - "datasource": { - "uid": "Loki" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 16 - }, - "options": { - "showLabels": false, - "showCommonLabels": false, - "showTime": false, - "showLogContextToggle": false, - "wrapLogMessage": false, - "prettifyLogMessage": false, - "enableLogDetails": false, - "sortOrder": "", - "dedupStrategy": "" - }, - "fieldConfig": { - "defaults": { - "noValue": "No data" - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "interval", - "name": "interval", - "label": "Interval", - "description": "", - "query": "30s,1m,5m,15m,30m,1h,6h,12h", - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - } - }, - { - "type": "query", - "name": "env", - "label": "Environment", - "description": "", - "query": "label_values(up, env)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "cluster", - "label": "Cluster", - "description": "", - "query": "label_values(up{env=\"$env\"}, cluster)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "blockchain", - "label": "Blockchain", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\"}, blockchain)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "product", - "label": "Product", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", blockchain=\"$blockchain\"}, product)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "network_type", - "label": "Network Type", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", blockchain=\"$blockchain\", product=\"$product\"}, network_type)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "component", - "label": "Component", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", blockchain=\"$blockchain\", network_type=\"$network_type\"}, component)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "service", - "label": "Service", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", blockchain=\"$blockchain\", network_type=\"$network_type\", component=\"$component\"}, service)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "service_id", - "label": "Service ID", - "description": "", - "query": "label_values(health{cluster=\"$cluster\", blockchain=\"$blockchain\", network_type=\"$network_type\", component=\"$component\", service=\"$service\"}, service_id)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": true, - "sort": 1, - "includeAll": true - } - ] - }, - "annotations": {} - }, - "Alerts": null, - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/dashboards/core-node/component.go b/observability-lib/dashboards/core-node/component.go deleted file mode 100644 index 8374bad53..000000000 --- a/observability-lib/dashboards/core-node/component.go +++ /dev/null @@ -1,2296 +0,0 @@ -package corenode - -import ( - "fmt" - "strconv" - - "github.com/grafana/grafana-foundation-sdk/go/alerting" - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/common" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - "github.com/grafana/grafana-foundation-sdk/go/expr" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -// NewDashboard creates a DON dashboard for the given OCR version -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - if props.Platform == "" { - return nil, fmt.Errorf("Platform is required") - } - - if props.MetricsDataSource == nil { - return nil, fmt.Errorf("MetricsDataSource is required") - } else { - if props.MetricsDataSource.Name == "" { - return nil, fmt.Errorf("MetricsDataSource.Name is required") - } - if props.MetricsDataSource.UID == "" { - return nil, fmt.Errorf("MetricsDataSource.UID is required") - } - } - - if props.LogsDataSource == nil { - return nil, fmt.Errorf("LogsDataSource is required") - } else { - if props.LogsDataSource.Name == "" { - return nil, fmt.Errorf("LogsDataSource.Name is required") - } - if props.LogsDataSource.UID == "" { - return nil, fmt.Errorf("LogsDataSource.UID is required") - } - } - - props.platformOpts = platformPanelOpts(props.Platform) - if props.Tested { - props.platformOpts.LabelQuery = "" - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"Core", "Node"}, - Refresh: "30s", - TimeFrom: "now-30m", - TimeTo: "now", - AlertsTags: props.AlertsTags, - }) - - if props.SlackChannel != "" && props.SlackWebhookURL != "" { - builder.AddContactPoint(grafana.NewContactPoint(&grafana.ContactPointOptions{ - Name: "chainlink-slack", - Type: "slack", - Settings: map[string]interface{}{ - "url": props.SlackWebhookURL, - "recipient": props.SlackChannel, - "username": "Chainlink Alerts", - "title": `{{ template "slack.chainlink.title" . }}`, - "text": `{{ template "slack.chainlink.text" . }}`, - "color": `{{ template "slack.chainlink.color" . }}`, - }, - })) - - notificationPolicySlackOptions := &grafana.NotificationPolicyOptions{ - Receiver: "chainlink-slack", - GroupBy: []string{"grafana_folder", "alertname"}, - Continue: grafana.Pointer(true), - } - for name, value := range props.AlertsTags { - notificationPolicySlackOptions.ObjectMatchers = append(notificationPolicySlackOptions.ObjectMatchers, alerting.ObjectMatcher{name, "=", value}) - } - builder.AddNotificationPolicy(grafana.NewNotificationPolicy(notificationPolicySlackOptions)) - } - - builder.AddVars(vars(props)...) - - builder.AddRow("Headlines") - builder.AddPanel(headlines(props)...) - - builder.AddRow("AppDBConnections") - builder.AddPanel(appDBConnections(props)...) - - builder.AddRow("SQLQueries") - builder.AddPanel(sqlQueries(props)...) - - builder.AddRow("HeadTracker") - builder.AddPanel(headTracker(props)...) - - builder.AddRow("HeadReporter") - builder.AddPanel(headReporter(props)...) - - builder.AddRow("TxManager") - builder.AddPanel(txManager(props)...) - - builder.AddRow("LogPoller") - builder.AddPanel(logPoller(props)...) - - builder.AddRow("Feeds Jobs") - builder.AddPanel(feedsJobs(props)...) - - builder.AddRow("Mailbox") - builder.AddPanel(mailbox(props)...) - - builder.AddRow("Logs Counters") - builder.AddPanel(logsCounters(props)...) - - builder.AddRow("Logs Rate") - builder.AddPanel(logsRate(props)...) - - builder.AddRow("EvmPoolLifecycle") - builder.AddPanel(evmPoolLifecycle(props)...) - - builder.AddRow("Node RPC State") - builder.AddPanel(nodesRPC(props)...) - - builder.AddRow("EVM Pool RPC Node Metrics (App)") - builder.AddPanel(evmNodeRPC(props)...) - - builder.AddRow("EVM Pool RPC Node Latencies (App)") - builder.AddPanel(evmPoolRPCNodeLatencies(props)...) - - builder.AddRow("Block History Estimator") - builder.AddPanel(evmBlockHistoryEstimator(props)...) - - builder.AddRow("Pipeline Metrics (Runner)") - builder.AddPanel(pipelines(props)...) - - builder.AddRow("HTTP API") - builder.AddPanel(httpAPI(props)...) - - builder.AddRow("PromHTTP") - builder.AddPanel(promHTTP(props)...) - - builder.AddRow("Go Metrics") - builder.AddPanel(goMetrics(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - if p.platformOpts.Platform == "kubernetes" { - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Environment", - Name: "env", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds, env)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Cluster", - Name: "cluster", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env"}, cluster)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Namespace", - Name: "namespace", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster"}, namespace)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Blockchain", - Name: "blockchain", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster", namespace="$namespace"}, blockchain)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Product", - Name: "product", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster", namespace="$namespace", blockchain="$blockchain"}, product)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Network Type", - Name: "network_type", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster", namespace="$namespace", blockchain="$blockchain", product="$product"}, network_type)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Job", - Name: "job", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster", namespace="$namespace", blockchain="$blockchain", product="$product", network_type="$network_type"}, job)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Pod", - Name: "pod", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(uptime_seconds{env="$env", cluster="$cluster", namespace="$namespace", job="$job"}, pod)`, - Multi: true, - IncludeAll: true, - })) - } else { - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Instance", - Name: "instance", - }, - Datasource: p.MetricsDataSource.Name, - Query: fmt.Sprintf("label_values(%s)", p.platformOpts.LabelFilter), - Multi: true, - IncludeAll: true, - })) - } - - return variables -} - -func healthAverageAlertRule(p *Props, threshold float64, tags map[string]string) grafana.AlertOptions { - return grafana.AlertOptions{ - Title: `Health Avg by Service is less than ` + strconv.FormatFloat(threshold, 'f', -1, 64) + `%`, - Summary: `Uptime less than ` + strconv.FormatFloat(threshold, 'f', -1, 64) + `% over last 15 minutes on one component in a Node`, - Description: `Component {{ index $labels "service_id" }} uptime in the last 15m is {{ index $values "C" }}%`, - RunbookURL: "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - For: "15m", - Tags: tags, - Query: []grafana.RuleQuery{ - { - Expr: `health{` + p.AlertsFilters + `}`, - RefID: "A", - Datasource: p.MetricsDataSource.UID, - }, - }, - QueryRefCondition: "D", - Condition: []grafana.ConditionQuery{ - { - RefID: "B", - ReduceExpression: &grafana.ReduceExpression{ - Expression: "A", - Reducer: expr.TypeReduceReducerMean, - }, - }, - { - RefID: "C", - MathExpression: &grafana.MathExpression{ - Expression: "$B * 100", - }, - }, - { - RefID: "D", - ThresholdExpression: &grafana.ThresholdExpression{ - Expression: "C", - ThresholdConditionsOptions: grafana.ThresholdConditionsOption{ - Params: []float64{threshold}, - Type: grafana.TypeThresholdTypeLt, - }, - }, - }, - }, - } -} - -func headlines(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "App Version", - Description: "app version with commit and branch links", - Span: 12, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `version{` + p.platformOpts.LabelQuery + `}`, - Legend: "Version: {{version}} https://github.com/smartcontractkit/chainlink/commit/{{commit}} https://github.com/smartcontractkit/chainlink/tree/release/{{version}}", - Instant: true, - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - TextMode: common.BigValueTextModeName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Uptime", - Description: "instance uptime", - Span: 12, - Height: 4, - Decimals: 2, - Unit: "s", - Query: []grafana.Query{ - { - Expr: `uptime_seconds{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "ETH Balance Summary", - Span: 12, - Height: 4, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `sum(eth_balance{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, account)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{account}}`, - Instant: true, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - }, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Solana Balance Summary", - Span: 12, - Height: 4, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `sum(solana_balance{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, account)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{account}}`, - Instant: true, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - }, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Health Avg by Service over 15m", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * (avg(avg_over_time(health{` + p.platformOpts.LabelQuery + `}[15m])) by (` + p.platformOpts.LabelFilter + `, service_id, version, service, cluster, env))`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{service_id}}`, - }, - }, - Min: grafana.Pointer[float64](0), - Max: grafana.Pointer[float64](100), - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "green"}, - {Value: grafana.Pointer[float64](50), Color: "red"}, - {Value: grafana.Pointer[float64](70), Color: "orange"}, - {Value: grafana.Pointer[float64](90), Color: "green"}, - }, - }, - }, - ThresholdStyle: common.GraphThresholdsStyleModeDashed, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - AlertsOptions: []grafana.AlertOptions{ - healthAverageAlertRule(p, 90, map[string]string{"severity": "info"}), - healthAverageAlertRule(p, 70, map[string]string{"severity": "warning"}), - healthAverageAlertRule(p, 50, map[string]string{"severity": "critical"}), - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Health Avg by Service over 15m with health < 90%", - Description: "Only displays services with health average < 90%", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * avg(avg_over_time(health{` + p.platformOpts.LabelQuery + `}[15m])) by (` + p.platformOpts.LabelFilter + `, service_id, version, service, cluster, env) < 90`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{service_id}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "green"}, - {Value: grafana.Pointer[float64](1), Color: "red"}, - {Value: grafana.Pointer[float64](80), Color: "orange"}, - {Value: grafana.Pointer[float64](99), Color: "green"}, - }, - }, - NoValue: "All services healthy", - }, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewLogPanel(&grafana.LogPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.LogsDataSource.Name, - Title: "Logs with severity >= error", - Span: 24, - Height: 10, - Query: []grafana.Query{ - { - Expr: `{env="${env}", cluster="${cluster}", product="${product}", network_type="${network_type}", namespace="${namespace}", pod="${pod}"} | json | level=~"(error|panic|fatal|crit)"`, - Legend: "", - }, - }, - }, - PrettifyJSON: true, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "ETH Balance", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `sum(eth_balance{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, account)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{account}}`, - }, - }, - }, - AlertsOptions: []grafana.AlertOptions{ - { - Summary: `ETH Balance is lower than threshold`, - Description: `ETH Balance critically low at {{ index $values "A" }} on {{ index $labels "` + p.platformOpts.LabelFilter + `" }}`, - RunbookURL: "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - For: "15m", - NoDataState: alerting.RuleNoDataStateOK, - Tags: map[string]string{ - "severity": "critical", - }, - Query: []grafana.RuleQuery{ - { - Expr: `eth_balance{` + p.AlertsFilters + `}`, - Instant: true, - RefID: "A", - Datasource: p.MetricsDataSource.UID, - }, - }, - QueryRefCondition: "B", - Condition: []grafana.ConditionQuery{ - { - RefID: "B", - ThresholdExpression: &grafana.ThresholdExpression{ - Expression: "A", - ThresholdConditionsOptions: grafana.ThresholdConditionsOption{ - Params: []float64{1}, - Type: grafana.TypeThresholdTypeLt, - }, - }, - }, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "SOL Balance", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `sum(solana_balance{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, account)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{account}}`, - }, - }, - }, - AlertsOptions: []grafana.AlertOptions{ - { - Summary: `Solana Balance is lower than threshold`, - Description: `Solana Balance critically low at {{ index $values "A" }} on {{ index $labels "` + p.platformOpts.LabelFilter + `" }}`, - RunbookURL: "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - For: "15m", - NoDataState: alerting.RuleNoDataStateOK, - Tags: map[string]string{ - "severity": "critical", - }, - Query: []grafana.RuleQuery{ - { - Expr: `solana_balance{` + p.AlertsFilters + `}`, - Instant: true, - RefID: "A", - Datasource: p.MetricsDataSource.UID, - }, - }, - QueryRefCondition: "B", - Condition: []grafana.ConditionQuery{ - { - RefID: "B", - ThresholdExpression: &grafana.ThresholdExpression{ - Expression: "A", - ThresholdConditionsOptions: grafana.ThresholdConditionsOption{ - Params: []float64{1}, - Type: grafana.TypeThresholdTypeLt, - }, - }, - }, - }, - }, - }, - })) - - if p.platformOpts.Platform == "kubernetes" { - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Utilisation (from requests)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: `{{pod}}`, - Instant: true, - }, - }, - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Utilisation (from limits)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: `{{pod}}`, - Instant: true, - }, - }, - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Utilisation (from requests)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", cluster="$cluster", namespace="$namespace", pod="$pod", image!=""}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: `{{pod}}`, - Instant: true, - }, - }, - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Utilisation (from limits)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", cluster="$cluster", namespace="$namespace", pod="$pod", container!="", image!=""}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: `{{pod}}`, - Instant: true, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Usage", - Span: 12, - Height: 8, - Decimals: 3, - Query: []grafana.Query{ - { - Expr: `sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{pod=~"$pod", namespace=~"${namespace}"}) by (pod)`, - Legend: "{{pod}}", - }, - { - Expr: `sum(kube_pod_container_resource_requests{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="cpu"})`, - Legend: "Requests", - }, - { - Expr: `sum(kube_pod_container_resource_limits{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="cpu"})`, - Legend: "Limits", - }, - }, - }, - ScaleDistribution: common.ScaleDistributionLog, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Usage", - Span: 12, - Height: 8, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `sum(container_memory_rss{pod=~"$pod", namespace=~"${namespace}", container!=""}) by (pod)`, - Legend: "{{pod}}", - }, - { - Expr: `sum(kube_pod_container_resource_requests{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="memory"})`, - Legend: "Requests", - }, - { - Expr: `sum(kube_pod_container_resource_limits{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="memory"})`, - Legend: "Limits", - }, - }, - }, - ScaleDistribution: common.ScaleDistributionLog, - })) - } - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Open File Descriptors", - Span: 6, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `process_open_fds{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - GraphMode: common.BigValueGraphModeArea, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Go Version", - Span: 4, - Height: 4, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `go_info{` + p.platformOpts.LabelQuery + `}`, - Legend: "{{exported_version}}", - Instant: true, - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - TextMode: common.BigValueTextModeName, - })) - - return panels -} - -func appDBConnections(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "DB Connections", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "Conn", - Query: []grafana.Query{ - { - Expr: `sum(db_conns_max{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - Max`, - }, - { - Expr: `sum(db_conns_open{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - Open`, - }, - { - Expr: `sum(db_conns_used{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - Used`, - }, - { - Expr: `sum(db_conns_wait{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - Wait`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "DB Wait Count", - Span: 12, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(db_wait_count{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "DB Wait Time", - Span: 12, - Height: 6, - Unit: "Sec", - Query: []grafana.Query{ - { - Expr: `sum(db_wait_time_seconds{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - return panels -} - -func sqlQueries(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "SQL Query Timeout Percent", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(0.9, sum(rate(sql_query_timeout_percent_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le))`, - Legend: "p90", - }, - { - Expr: `histogram_quantile(0.95, sum(rate(sql_query_timeout_percent_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le))`, - Legend: "p95", - }, - { - Expr: `histogram_quantile(0.99, sum(rate(sql_query_timeout_percent_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le))`, - Legend: "p99", - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - return panels -} - -func headTracker(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Head Tracker Current Head", - Span: 18, - Height: 6, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `sum(head_tracker_current_head{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Head Tracker Current Head Summary", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `head_tracker_current_head{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - Instant: true, - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Head Tracker Heads Received Rate", - Span: 24, - Height: 6, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `rate(head_tracker_heads_received{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - AlertsOptions: []grafana.AlertOptions{ - { - Summary: `No Headers Received`, - Description: `{{ index $labels "` + p.platformOpts.LabelFilter + `" }} on ChainID {{ index $labels "ChainID" }} has received {{ index $values "A" }} heads over 10 minutes.`, - RunbookURL: "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - For: "10m", - NoDataState: alerting.RuleNoDataStateOK, - Tags: map[string]string{ - "severity": "critical", - }, - Query: []grafana.RuleQuery{ - { - Expr: `increase(head_tracker_heads_received{` + p.AlertsFilters + `}[10m])`, - Instant: true, - RefID: "A", - Datasource: p.MetricsDataSource.UID, - }, - }, - QueryRefCondition: "B", - Condition: []grafana.ConditionQuery{ - { - RefID: "B", - ThresholdExpression: &grafana.ThresholdExpression{ - Expression: "A", - ThresholdConditionsOptions: grafana.ThresholdConditionsOption{ - Params: []float64{1}, - Type: grafana.TypeThresholdTypeLt, - }, - }, - }, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Head Tracker Very Old Head", - Span: 12, - Height: 6, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `head_tracker_very_old_head{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Head Tracker Connection Errors Rate", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `rate(head_tracker_connection_errors{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} - -func headReporter(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Unconfirmed Transactions", - Span: 8, - Height: 6, - Unit: "Tx", - Query: []grafana.Query{ - { - Expr: `sum(unconfirmed_transactions{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Unconfirmed TX Age", - Span: 8, - Height: 6, - Unit: "s", - Query: []grafana.Query{ - { - Expr: `sum(max_unconfirmed_tx_age{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Unconfirmed TX Blocks", - Span: 8, - Height: 6, - Unit: "Blocks", - Query: []grafana.Query{ - { - Expr: `sum(max_unconfirmed_blocks{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} - -func txManager(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Confirmed", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_num_confirmed_transactions{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Successful", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_num_successful_transactions{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Reverted", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_num_tx_reverted{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Gas Bumps", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_num_gas_bumps{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Forwarded", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_fwd_tx_count{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Attempts", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_tx_attempt_count{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Gas Bump Exceeds Limit", - Span: 6, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(tx_manager_gas_bump_exceeds_limit{` + p.platformOpts.LabelQuery + `}) by (blockchain, chainID, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Time Until Broadcast", - Description: "The amount of time elapsed from when a transaction is enqueued to until it is broadcast", - Span: 6, - Height: 6, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(0.9, sum(rate(tx_manager_time_until_tx_broadcast_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le, ` + p.platformOpts.LabelFilter + `, blockchain, chainID)) / 1e6`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "TX Manager Time Until Confirmed", - Description: "The amount of time elapsed from a transaction being broadcast to being included in a block", - Span: 6, - Height: 6, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(0.9, sum(rate(tx_manager_time_until_tx_confirmed_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le, ` + p.platformOpts.LabelFilter + `, blockchain, chainID)) / 1e6`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{blockchain}} - {{chainID}}`, - }, - }, - }, - })) - - return panels -} - -func logPoller(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Goroutines per ChainId", - Description: "goroutines per chainId", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `count(log_poller_query_duration_sum{` + p.platformOpts.LabelQuery + `}) by (evmChainID)`, - Legend: "chainId: {{evmChainID}}", - }, - }, - }, - ColorMode: common.BigValueColorModeValue, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "RPS", - Description: "requests per second", - Span: 12, - Height: 6, - Decimals: 2, - Unit: "reqps", - Query: []grafana.Query{ - { - Expr: `avg by (query, ` + p.platformOpts.LabelFilter + `) (sum by (query, job) (rate(log_poller_query_duration_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])))`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{query}}`, - }, - { - Expr: `avg (sum by(` + p.platformOpts.LabelFilter + `) (rate(log_poller_query_duration_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])))`, - Legend: "Total", - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "RPS by Type", - Span: 12, - Height: 6, - Decimals: 2, - Unit: "reqps", - Query: []grafana.Query{ - { - Expr: `avg by (` + p.platformOpts.LabelFilter + `, type) (sum by (type, ` + p.platformOpts.LabelFilter + `) (rate(log_poller_query_duration_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])))`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{type}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Avg number of logs returned", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `avg by (` + p.platformOpts.LabelFilter + `, query) (log_poller_query_dataset_size{` + p.platformOpts.LabelQuery + `})`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{query}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Max number of logs returned", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `max by (` + p.platformOpts.LabelFilter + `, query) (log_poller_query_dataset_size{` + p.platformOpts.LabelQuery + `})`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{query}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Logs returned by chain", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `max by (evmChainID) (log_poller_query_dataset_size{` + p.platformOpts.LabelQuery + `})`, - Legend: "{{evmChainID}}", - }, - }, - }, - })) - - quantiles := []string{"0.5", "0.9", "0.99"} - for _, quantile := range quantiles { - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: `Queries duration by query ` + quantile + ` quantile`, - Span: 24, - Height: 6, - Decimals: 2, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(` + quantile + `, sum(rate(log_poller_query_duration_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (le, ` + p.platformOpts.LabelFilter + `, query)) / 1e6`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{query}}`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - } - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Number of logs inserted", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `avg by (evmChainID) (log_poller_logs_inserted{` + p.platformOpts.LabelQuery + `})`, - Legend: "{{evmChainID}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Logs insertion rate", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `avg by (evmChainID) (rate(log_poller_logs_inserted{` + p.platformOpts.LabelQuery + `}[$__rate_interval]))`, - Legend: "{{evmChainID}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Number of blocks inserted", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `avg by (evmChainID) (log_poller_blocks_inserted{` + p.platformOpts.LabelQuery + `})`, - Legend: "{{evmChainID}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Blocks insertion rate", - Span: 12, - Height: 6, - Decimals: 2, - Query: []grafana.Query{ - { - Expr: `avg by (evmChainID) (rate(log_poller_blocks_inserted{` + p.platformOpts.LabelQuery + `}[$__rate_interval]))`, - Legend: "{{evmChainID}}", - }, - }, - }, - })) - - return panels -} - -func feedsJobs(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Feeds Job Proposal Requests", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(feeds_job_proposal_requests{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Feeds Job Proposal Count", - Description: "", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(feeds_job_proposal_count{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} - -func mailbox(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Mailbox Load Percent", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `sum(mailbox_load_percent{` + p.platformOpts.LabelQuery + `}) by (capacity, name, ` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - Capacity: {{capacity}} - {{name}}`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - return panels -} - -func logsCounters(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - logStatuses := []string{"panic", "fatal", "critical", "warn", "error"} - for _, status := range logStatuses { - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Logs Counter - " + status, - Span: 8, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(log_` + status + `_count{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - ` + status, - }, - }, - }, - })) - } - - return panels -} - -func logsRate(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - logStatuses := []string{"panic", "fatal", "critical", "warn", "error"} - for _, status := range logStatuses { - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Logs Rate - " + status, - Span: 8, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(rate(log_` + status + `_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - error`, - }, - }, - }, - })) - } - - return panels -} - -func evmPoolLifecycle(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool Highest Seen Block", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_highest_seen_block{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool Num Seen Blocks", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_num_seen_blocks{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool Node Polls Total", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_polls_total{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool Node Polls Failed", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_polls_failed{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool Node Polls Success", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "Block", - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_polls_success{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} - -func nodesRPC(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - nodeRPCStates := []string{"Alive", "Closed", "Dialed", "InvalidChainID", "OutOfSync", "Undialed", "Unreachable", "Unusable"} - for _, state := range nodeRPCStates { - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Node RPC " + state, - Span: 6, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(multi_node_states{` + p.platformOpts.LabelQuery + `state="` + state + `"}) by (` + p.platformOpts.LabelFilter + `, chainId)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{chainId}}`, - }, - }, - }, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - } - - return panels -} - -func evmNodeRPC(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node Calls Success Rate", - Span: 24, - Height: 6, - Decimals: 2, - Unit: "percentunit", - Max: grafana.Pointer[float64](1), - Query: []grafana.Query{ - { - Expr: `sum(increase(evm_pool_rpc_node_calls_success{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_calls_total{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `, evmChainID, nodeName)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{nodeName}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.8), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node Dials Failure Rate", - Span: 24, - Height: 6, - Decimals: 2, - Unit: "percentunit", - Max: grafana.Pointer[float64](1), - Query: []grafana.Query{ - { - Expr: `sum(increase(evm_pool_rpc_node_dials_failed{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_calls_total{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `, evmChainID, nodeName)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{evmChainID}} - {{nodeName}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.8), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node Transitions", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_num_transitions_to_alive{` + p.platformOpts.LabelQuery + `}`, - Legend: "Alive", - }, - { - Expr: `evm_pool_rpc_node_num_transitions_to_in_sync{` + p.platformOpts.LabelQuery + `}`, - Legend: "InSync", - }, - { - Expr: `evm_pool_rpc_node_num_transitions_to_out_of_sync{` + p.platformOpts.LabelQuery + `}`, - Legend: "OutOfSync", - }, - { - Expr: `evm_pool_rpc_node_num_transitions_to_unreachable{` + p.platformOpts.LabelQuery + `}`, - Legend: "UnReachable", - }, - { - Expr: `evm_pool_rpc_node_num_transitions_to_invalid_chain_id{` + p.platformOpts.LabelQuery + `}`, - Legend: "InvalidChainID", - }, - { - Expr: `evm_pool_rpc_node_num_transitions_to_unusable{` + p.platformOpts.LabelQuery + `}`, - Legend: "TransitionToUnusable", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node States", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `evm_pool_rpc_node_states{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{evmChainID}} - {{state}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node Verifies Success Rate", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `sum(increase(evm_pool_rpc_node_verifies_success{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_verifies{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, evmChainID, nodeName) * 100`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{evmChainID}} - {{nodeName}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "EVM Pool RPC Node Verifies Failure Rate", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `sum(increase(evm_pool_rpc_node_verifies_failed{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_verifies{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, evmChainID, nodeName) * 100`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{evmChainID}} - {{nodeName}}`, - }, - }, - }, - })) - - return panels -} - -func evmPoolRPCNodeLatencies(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - quantiles := []string{"0.90", "0.95", "0.99"} - for _, quantile := range quantiles { - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: `EVM Pool RPC Node Calls Latency ` + quantile + ` quantile`, - Span: 24, - Height: 6, - Decimals: 1, - Unit: "ms", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(` + quantile + `, sum(rate(evm_pool_rpc_node_rpc_call_time_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LabelFilter + `, le, rpcCallName)) / 1e6`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{rpcCallName}}`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - } - - return panels -} - -func evmBlockHistoryEstimator(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Gas Updater All Gas Price Percentiles", - Description: "Gas price at given percentile", - Span: 24, - Height: 6, - Unit: "gwei", - Query: []grafana.Query{ - { - Expr: `sum(gas_updater_all_gas_price_percentiles{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, evmChainID, percentile)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{evmChainID}} - {{percentile}}`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Gas Updater All Tip Cap Percentiles", - Description: "Tip cap at given percentile", - Span: 24, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(gas_updater_all_tip_cap_percentiles{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `, evmChainID, percentile)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}} - {{evmChainID}} - {{percentile}}`, - }, - }, - }, - LegendOptions: &grafana.LegendOptions{ - DisplayMode: common.LegendDisplayModeList, - Placement: common.LegendPlacementRight, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Gas Updater Set Gas Price", - Span: 12, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(gas_updater_set_gas_price{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Gas Updater Set Tip Cap", - Span: 12, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(gas_updater_set_tip_cap{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Gas Updater Current Base Fee", - Span: 12, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(gas_updater_current_base_fee{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Block History Estimator Connectivity Failure Count", - Span: 12, - Height: 6, - Query: []grafana.Query{ - { - Expr: `sum(block_history_estimator_connectivity_failure_count{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LabelFilter + `)`, - Legend: `{{` + p.platformOpts.LabelFilter + `}}`, - }, - }, - }, - })) - - return panels -} - -func pipelines(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Pipeline Task Execution Time", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "s", - Query: []grafana.Query{ - { - Expr: `pipeline_task_execution_time{` + p.platformOpts.LabelQuery + `} / 1e6`, - Legend: `{{` + p.platformOpts.LegendString + `}} JobID: {{job_id}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Pipeline Run Errors", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `pipeline_run_errors{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} JobID: {{job_id}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Pipeline Run Total Time to Completion", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "s", - Query: []grafana.Query{ - { - Expr: `pipeline_run_total_time_to_completion{` + p.platformOpts.LabelQuery + `} / 1e6`, - Legend: `{{` + p.platformOpts.LegendString + `}} JobID: {{job_id}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Pipeline Tasks Total Finished", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `pipeline_tasks_total_finished{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} JobID: {{job_id}}`, - }, - }, - }, - })) - - return panels -} - -func httpAPI(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Request Duration p95", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "s", - Query: []grafana.Query{ - { - Expr: `histogram_quantile(0.95, sum(rate(service_gonic_request_duration_bucket{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, le, path, method))`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{method}} - {{path}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Request Total Rate over interval", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(rate(service_gonic_requests_total{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, path, method, code)`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{method}} - {{path}} - {{code}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Average Request Size", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `avg(rate(service_gonic_request_size_bytes_sum{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `)/avg(rate(service_gonic_request_size_bytes_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Response Size", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `avg(rate(service_gonic_response_size_bytes_sum{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `)/avg(rate(service_gonic_response_size_bytes_count{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} - -func promHTTP(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "HTTP rate by return code", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(rate(promhttp_metric_handler_requests_total{` + p.platformOpts.LabelQuery + `}[$__rate_interval])) by (` + p.platformOpts.LegendString + `, code)`, - Legend: `{{` + p.platformOpts.LegendString + `}} - {{code}}`, - }, - }, - }, - })) - - return panels -} - -func goMetrics(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Threads", - Span: 24, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `sum(go_threads{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LegendString + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Heap Allocations Stats", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `sum(go_memstats_heap_alloc_bytes{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LegendString + `)`, - Legend: "", - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Heap allocations Graph", - Span: 24, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `sum(go_memstats_heap_alloc_bytes{` + p.platformOpts.LabelQuery + `}) by (` + p.platformOpts.LegendString + `)`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Heap Usage", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `go_memstats_heap_alloc_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Alloc`, - }, - { - Expr: `go_memstats_heap_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Sys`, - }, - { - Expr: `go_memstats_heap_idle_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Idle`, - }, - { - Expr: `go_memstats_heap_inuse_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - InUse`, - }, - { - Expr: `go_memstats_heap_released_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Released`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory in Off-Heap", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `go_memstats_mspan_inuse_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Total InUse`, - }, - { - Expr: `go_memstats_mspan_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Total Sys`, - }, - { - Expr: `go_memstats_mcache_inuse_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Cache InUse`, - }, - { - Expr: `go_memstats_mcache_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Cache Sys`, - }, - { - Expr: `go_memstats_buck_hash_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Hash Sys`, - }, - { - Expr: `go_memstats_gc_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - GC Sys`, - }, - { - Expr: `go_memstats_other_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - bytes of memory are used for other runtime allocations`, - }, - { - Expr: `go_memstats_next_gc_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Next GC`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory in Stack", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `go_memstats_stack_inuse_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - InUse`, - }, - { - Expr: `go_memstats_stack_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}} - Sys`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Total Used Memory", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `go_memstats_sys_bytes{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Number of Live Objects", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `go_memstats_mallocs_total{` + p.platformOpts.LabelQuery + `} - go_memstats_frees_total{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Rate of Objects Allocated", - Span: 12, - Height: 6, - Decimals: 1, - Query: []grafana.Query{ - { - Expr: `rate(go_memstats_mallocs_total{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Rate of a Pointer Dereferences", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "ops", - Query: []grafana.Query{ - { - Expr: `rate(go_memstats_lookups_total{` + p.platformOpts.LabelQuery + `}[1m])`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Goroutines", - Span: 12, - Height: 6, - Decimals: 1, - Unit: "ops", - Query: []grafana.Query{ - { - Expr: `go_goroutines{` + p.platformOpts.LabelQuery + `}`, - Legend: `{{` + p.platformOpts.LegendString + `}}`, - }, - }, - }, - })) - - return panels -} diff --git a/observability-lib/dashboards/core-node/component_test.go b/observability-lib/dashboards/core-node/component_test.go deleted file mode 100644 index 965acc493..000000000 --- a/observability-lib/dashboards/core-node/component_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package corenode_test - -import ( - "flag" - "os" - "testing" - - corenode "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/core-node" - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - "github.com/stretchr/testify/require" -) - -var update = flag.Bool("update", false, "update golden test files") - -const fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := corenode.NewDashboard(&corenode.Props{ - Name: "Core Node Dashboard", - Platform: grafana.TypePlatformDocker, - MetricsDataSource: grafana.NewDataSource("Prometheus", "1"), - LogsDataSource: grafana.NewDataSource("Loki", "2"), - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := corenode.NewDashboard(&corenode.Props{ - Name: "Core Node Dashboard", - Platform: grafana.TypePlatformDocker, - MetricsDataSource: grafana.NewDataSource("Prometheus", "1"), - LogsDataSource: grafana.NewDataSource("Loki", "2"), - Tested: true, - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "Core Node Dashboard", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/core-node/platform.go b/observability-lib/dashboards/core-node/platform.go deleted file mode 100644 index fbd7b6c6c..000000000 --- a/observability-lib/dashboards/core-node/platform.go +++ /dev/null @@ -1,55 +0,0 @@ -package corenode - -import ( - "fmt" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type platformOpts struct { - // Platform is infrastructure deployment platform: docker or k8s - Platform grafana.TypePlatform - LabelFilters map[string]string - LabelFilter string - LegendString string - LabelQuery string -} - -type Props struct { - Name string // Name is the name of the dashboard - Platform grafana.TypePlatform // Platform is infrastructure deployment platform: docker or k8s - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics - LogsDataSource *grafana.DataSource // LogsDataSource is the datasource for querying logs - SlackChannel string // SlackChannel is the channel to send alerts to - SlackWebhookURL string // SlackWebhookURL is the URL to send alerts to - AlertsTags map[string]string // AlertsTags is the tags to map with notification policy - AlertsFilters string // AlertsFilters is the filters to apply to alerts - platformOpts platformOpts - Tested bool -} - -// PlatformPanelOpts generate different queries for "docker" and "k8s" deployment platforms -func platformPanelOpts(platform grafana.TypePlatform) platformOpts { - po := platformOpts{ - LabelFilters: map[string]string{}, - Platform: platform, - } - switch platform { - case grafana.TypePlatformKubernetes: - po.LabelFilters["namespace"] = `=~"${namespace}"` - po.LabelFilters["job"] = `=~"${job}"` - po.LabelFilters["pod"] = `=~"${pod}"` - po.LabelFilter = "job" - po.LegendString = "pod" - case grafana.TypePlatformDocker: - po.LabelFilters["instance"] = `=~"${instance}"` - po.LabelFilter = "instance" - po.LegendString = "instance" - default: - panic(fmt.Sprintf("failed to generate Platform dependent queries, unknown platform: %s", platform)) - } - for key, value := range po.LabelFilters { - po.LabelQuery += key + value + ", " - } - return po -} diff --git a/observability-lib/dashboards/core-node/test-output.json b/observability-lib/dashboards/core-node/test-output.json deleted file mode 100644 index 7f43d7735..000000000 --- a/observability-lib/dashboards/core-node/test-output.json +++ /dev/null @@ -1,6353 +0,0 @@ -{ - "Dashboard": { - "title": "Core Node Dashboard", - "tags": [ - "Core", - "Node" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-30m", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "row", - "collapsed": false, - "title": "Headlines", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 1, - "targets": [ - { - "expr": "version{}", - "instant": true, - "range": false, - "format": "", - "legendFormat": "Version: {{version}} https://github.com/smartcontractkit/chainlink/commit/{{commit}} https://github.com/smartcontractkit/chainlink/tree/release/{{version}}", - "refId": "" - } - ], - "title": "App Version", - "description": "app version with commit and branch links", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 12, - "x": 0, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 2, - "targets": [ - { - "expr": "uptime_seconds{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Uptime", - "description": "instance uptime", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 12, - "x": 12, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "s", - "decimals": 2, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 3, - "targets": [ - { - "expr": "sum(eth_balance{}) by (instance, account)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{instance}} - {{account}}", - "refId": "" - } - ], - "title": "ETH Balance Summary", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 12, - "x": 0, - "y": 5 - }, - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 4, - "targets": [ - { - "expr": "sum(solana_balance{}) by (instance, account)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{instance}} - {{account}}", - "refId": "" - } - ], - "title": "Solana Balance Summary", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 12, - "x": 12, - "y": 5 - }, - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 5, - "targets": [ - { - "expr": "100 * (avg(avg_over_time(health{}[15m])) by (instance, service_id, version, service, cluster, env))", - "format": "", - "legendFormat": "{{instance}} - {{service_id}}", - "refId": "" - } - ], - "title": "Health Avg by Service over 15m", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 9 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "min": 0, - "max": 100, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "green" - }, - { - "value": 50, - "color": "red" - }, - { - "value": 70, - "color": "orange" - }, - { - "value": 90, - "color": "green" - } - ] - }, - "noValue": "No data", - "custom": { - "thresholdsStyle": { - "mode": "dashed" - }, - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 6, - "targets": [ - { - "expr": "100 * avg(avg_over_time(health{}[15m])) by (instance, service_id, version, service, cluster, env) \u003c 90", - "format": "", - "legendFormat": "{{instance}} - {{service_id}}", - "refId": "" - } - ], - "title": "Health Avg by Service over 15m with health \u003c 90%", - "description": "Only displays services with health average \u003c 90%", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 15 - }, - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "green" - }, - { - "value": 1, - "color": "red" - }, - { - "value": 80, - "color": "orange" - }, - { - "value": 99, - "color": "green" - } - ] - }, - "noValue": "All services healthy" - }, - "overrides": null - } - }, - { - "type": "logs", - "id": 7, - "targets": [ - { - "expr": "{env=\"${env}\", cluster=\"${cluster}\", product=\"${product}\", network_type=\"${network_type}\", namespace=\"${namespace}\", pod=\"${pod}\"} | json | level=~\"(error|panic|fatal|crit)\"", - "format": "", - "legendFormat": "", - "refId": "" - } - ], - "title": "Logs with severity \u003e= error", - "description": "", - "transparent": false, - "datasource": { - "uid": "Loki" - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 21 - }, - "options": { - "showLabels": false, - "showCommonLabels": false, - "showTime": false, - "showLogContextToggle": false, - "wrapLogMessage": false, - "prettifyLogMessage": true, - "enableLogDetails": false, - "sortOrder": "", - "dedupStrategy": "" - }, - "fieldConfig": { - "defaults": { - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 8, - "targets": [ - { - "expr": "sum(eth_balance{}) by (instance, account)", - "format": "", - "legendFormat": "{{instance}} - {{account}}", - "refId": "" - } - ], - "title": "ETH Balance", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 31 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 9, - "targets": [ - { - "expr": "sum(solana_balance{}) by (instance, account)", - "format": "", - "legendFormat": "{{instance}} - {{account}}", - "refId": "" - } - ], - "title": "SOL Balance", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 31 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 10, - "targets": [ - { - "expr": "process_open_fds{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Open File Descriptors", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 37 - }, - "options": { - "graphMode": "area", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 11, - "targets": [ - { - "expr": "go_info{}", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{exported_version}}", - "refId": "" - } - ], - "title": "Go Version", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 4, - "x": 6, - "y": 37 - }, - "options": { - "graphMode": "none", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "AppDBConnections", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 41 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 12, - "targets": [ - { - "expr": "sum(db_conns_max{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - Max", - "refId": "" - }, - { - "expr": "sum(db_conns_open{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - Open", - "refId": "" - }, - { - "expr": "sum(db_conns_used{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - Used", - "refId": "" - }, - { - "expr": "sum(db_conns_wait{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - Wait", - "refId": "" - } - ], - "title": "DB Connections", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 42 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Conn", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 13, - "targets": [ - { - "expr": "sum(db_wait_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "DB Wait Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 48 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 14, - "targets": [ - { - "expr": "sum(db_wait_time_seconds{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "DB Wait Time", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 48 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Sec", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "SQLQueries", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 54 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 15, - "targets": [ - { - "expr": "histogram_quantile(0.9, sum(rate(sql_query_timeout_percent_bucket{}[$__rate_interval])) by (le))", - "format": "", - "legendFormat": "p90", - "refId": "" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(sql_query_timeout_percent_bucket{}[$__rate_interval])) by (le))", - "format": "", - "legendFormat": "p95", - "refId": "" - }, - { - "expr": "histogram_quantile(0.99, sum(rate(sql_query_timeout_percent_bucket{}[$__rate_interval])) by (le))", - "format": "", - "legendFormat": "p99", - "refId": "" - } - ], - "title": "SQL Query Timeout Percent", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 55 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "HeadTracker", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 61 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 16, - "targets": [ - { - "expr": "sum(head_tracker_current_head{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Head Tracker Current Head", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 18, - "x": 0, - "y": 62 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 17, - "targets": [ - { - "expr": "head_tracker_current_head{}", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Head Tracker Current Head Summary", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 62 - }, - "options": { - "graphMode": "none", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 18, - "targets": [ - { - "expr": "rate(head_tracker_heads_received{}[1m])", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Head Tracker Heads Received Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 68 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 19, - "targets": [ - { - "expr": "head_tracker_very_old_head{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Head Tracker Very Old Head", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 74 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 20, - "targets": [ - { - "expr": "rate(head_tracker_connection_errors{}[1m])", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Head Tracker Connection Errors Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 74 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "HeadReporter", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 80 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 21, - "targets": [ - { - "expr": "sum(unconfirmed_transactions{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Unconfirmed Transactions", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 81 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Tx", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 22, - "targets": [ - { - "expr": "sum(max_unconfirmed_tx_age{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Unconfirmed TX Age", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 81 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "s", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 23, - "targets": [ - { - "expr": "sum(max_unconfirmed_blocks{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Unconfirmed TX Blocks", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 81 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Blocks", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "TxManager", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 87 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 24, - "targets": [ - { - "expr": "sum(tx_manager_num_confirmed_transactions{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Confirmed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 88 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 25, - "targets": [ - { - "expr": "sum(tx_manager_num_successful_transactions{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Successful", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 88 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 26, - "targets": [ - { - "expr": "sum(tx_manager_num_tx_reverted{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Reverted", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 88 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 27, - "targets": [ - { - "expr": "sum(tx_manager_num_gas_bumps{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Gas Bumps", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 88 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 28, - "targets": [ - { - "expr": "sum(tx_manager_fwd_tx_count{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Forwarded", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 94 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 29, - "targets": [ - { - "expr": "sum(tx_manager_tx_attempt_count{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Attempts", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 94 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 30, - "targets": [ - { - "expr": "sum(tx_manager_gas_bump_exceeds_limit{}) by (blockchain, chainID, instance)", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Gas Bump Exceeds Limit", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 94 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 31, - "targets": [ - { - "expr": "histogram_quantile(0.9, sum(rate(tx_manager_time_until_tx_broadcast_bucket{}[$__rate_interval])) by (le, instance, blockchain, chainID)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Time Until Broadcast", - "description": "The amount of time elapsed from when a transaction is enqueued to until it is broadcast", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 94 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 32, - "targets": [ - { - "expr": "histogram_quantile(0.9, sum(rate(tx_manager_time_until_tx_confirmed_bucket{}[$__rate_interval])) by (le, instance, blockchain, chainID)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{blockchain}} - {{chainID}}", - "refId": "" - } - ], - "title": "TX Manager Time Until Confirmed", - "description": "The amount of time elapsed from a transaction being broadcast to being included in a block", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 100 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "LogPoller", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 106 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 33, - "targets": [ - { - "expr": "count(log_poller_query_duration_sum{}) by (evmChainID)", - "format": "", - "legendFormat": "chainId: {{evmChainID}}", - "refId": "" - } - ], - "title": "Goroutines per ChainId", - "description": "goroutines per chainId", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 107 - }, - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 34, - "targets": [ - { - "expr": "avg by (query, instance) (sum by (query, job) (rate(log_poller_query_duration_count{}[$__rate_interval])))", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - }, - { - "expr": "avg (sum by(instance) (rate(log_poller_query_duration_count{}[$__rate_interval])))", - "format": "", - "legendFormat": "Total", - "refId": "" - } - ], - "title": "RPS", - "description": "requests per second", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 107 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "reqps", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 35, - "targets": [ - { - "expr": "avg by (instance, type) (sum by (type, instance) (rate(log_poller_query_duration_count{}[$__rate_interval])))", - "format": "", - "legendFormat": "{{instance}} - {{type}}", - "refId": "" - } - ], - "title": "RPS by Type", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 113 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "reqps", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 36, - "targets": [ - { - "expr": "avg by (instance, query) (log_poller_query_dataset_size{})", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - } - ], - "title": "Avg number of logs returned", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 113 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 37, - "targets": [ - { - "expr": "max by (instance, query) (log_poller_query_dataset_size{})", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - } - ], - "title": "Max number of logs returned", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 119 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 38, - "targets": [ - { - "expr": "max by (evmChainID) (log_poller_query_dataset_size{})", - "format": "", - "legendFormat": "{{evmChainID}}", - "refId": "" - } - ], - "title": "Logs returned by chain", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 119 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 39, - "targets": [ - { - "expr": "histogram_quantile(0.5, sum(rate(log_poller_query_duration_bucket{}[$__rate_interval])) by (le, instance, query)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - } - ], - "title": "Queries duration by query 0.5 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 125 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 40, - "targets": [ - { - "expr": "histogram_quantile(0.9, sum(rate(log_poller_query_duration_bucket{}[$__rate_interval])) by (le, instance, query)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - } - ], - "title": "Queries duration by query 0.9 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 131 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 41, - "targets": [ - { - "expr": "histogram_quantile(0.99, sum(rate(log_poller_query_duration_bucket{}[$__rate_interval])) by (le, instance, query)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{query}}", - "refId": "" - } - ], - "title": "Queries duration by query 0.99 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 137 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 42, - "targets": [ - { - "expr": "avg by (evmChainID) (log_poller_logs_inserted{})", - "format": "", - "legendFormat": "{{evmChainID}}", - "refId": "" - } - ], - "title": "Number of logs inserted", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 143 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 43, - "targets": [ - { - "expr": "avg by (evmChainID) (rate(log_poller_logs_inserted{}[$__rate_interval]))", - "format": "", - "legendFormat": "{{evmChainID}}", - "refId": "" - } - ], - "title": "Logs insertion rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 143 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 44, - "targets": [ - { - "expr": "avg by (evmChainID) (log_poller_blocks_inserted{})", - "format": "", - "legendFormat": "{{evmChainID}}", - "refId": "" - } - ], - "title": "Number of blocks inserted", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 149 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 45, - "targets": [ - { - "expr": "avg by (evmChainID) (rate(log_poller_blocks_inserted{}[$__rate_interval]))", - "format": "", - "legendFormat": "{{evmChainID}}", - "refId": "" - } - ], - "title": "Blocks insertion rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 149 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Feeds Jobs", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 155 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 46, - "targets": [ - { - "expr": "sum(feeds_job_proposal_requests{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Feeds Job Proposal Requests", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 156 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 47, - "targets": [ - { - "expr": "sum(feeds_job_proposal_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Feeds Job Proposal Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 156 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Mailbox", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 162 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 48, - "targets": [ - { - "expr": "sum(mailbox_load_percent{}) by (capacity, name, instance)", - "format": "", - "legendFormat": "{{instance}} - Capacity: {{capacity}} - {{name}}", - "refId": "" - } - ], - "title": "Mailbox Load Percent", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 163 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Logs Counters", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 169 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 49, - "targets": [ - { - "expr": "sum(log_panic_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - panic", - "refId": "" - } - ], - "title": "Logs Counter - panic", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 170 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 50, - "targets": [ - { - "expr": "sum(log_fatal_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - fatal", - "refId": "" - } - ], - "title": "Logs Counter - fatal", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 170 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 51, - "targets": [ - { - "expr": "sum(log_critical_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - critical", - "refId": "" - } - ], - "title": "Logs Counter - critical", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 170 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 52, - "targets": [ - { - "expr": "sum(log_warn_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - warn", - "refId": "" - } - ], - "title": "Logs Counter - warn", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 176 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 53, - "targets": [ - { - "expr": "sum(log_error_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Counter - error", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 176 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Logs Rate", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 182 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 54, - "targets": [ - { - "expr": "sum(rate(log_panic_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Rate - panic", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 183 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 55, - "targets": [ - { - "expr": "sum(rate(log_fatal_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Rate - fatal", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 183 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 56, - "targets": [ - { - "expr": "sum(rate(log_critical_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Rate - critical", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 183 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 57, - "targets": [ - { - "expr": "sum(rate(log_warn_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Rate - warn", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 189 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 58, - "targets": [ - { - "expr": "sum(rate(log_error_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}} - error", - "refId": "" - } - ], - "title": "Logs Rate - error", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 189 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "EvmPoolLifecycle", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 195 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 59, - "targets": [ - { - "expr": "evm_pool_rpc_node_highest_seen_block{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "EVM Pool Highest Seen Block", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 196 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 60, - "targets": [ - { - "expr": "evm_pool_rpc_node_num_seen_blocks{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "EVM Pool Num Seen Blocks", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 196 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 61, - "targets": [ - { - "expr": "evm_pool_rpc_node_polls_total{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "EVM Pool Node Polls Total", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 202 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 62, - "targets": [ - { - "expr": "evm_pool_rpc_node_polls_failed{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "EVM Pool Node Polls Failed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 202 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 63, - "targets": [ - { - "expr": "evm_pool_rpc_node_polls_success{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "EVM Pool Node Polls Success", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 208 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "Block", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Node RPC State", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 214 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 64, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Alive\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Alive", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 215 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 65, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Closed\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Closed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 215 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 66, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Dialed\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Dialed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 215 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 67, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"InvalidChainID\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC InvalidChainID", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 215 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 68, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"OutOfSync\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC OutOfSync", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 221 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 69, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Undialed\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Undialed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 221 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 70, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Unreachable\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Unreachable", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 221 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 71, - "targets": [ - { - "expr": "sum(multi_node_states{state=\"Unusable\"}) by (instance, chainId)", - "format": "", - "legendFormat": "{{instance}} - {{chainId}}", - "refId": "" - } - ], - "title": "Node RPC Unusable", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 221 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "EVM Pool RPC Node Metrics (App)", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 227 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 72, - "targets": [ - { - "expr": "sum(increase(evm_pool_rpc_node_calls_success{}[$__rate_interval])) by (instance, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_calls_total{}[$__rate_interval])) by (instance, evmChainID, nodeName)", - "format": "", - "legendFormat": "{{instance}} - {{nodeName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Calls Success Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 228 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "max": 1, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 73, - "targets": [ - { - "expr": "sum(increase(evm_pool_rpc_node_dials_failed{}[$__rate_interval])) by (instance, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_calls_total{}[$__rate_interval])) by (instance, evmChainID, nodeName)", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{nodeName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Dials Failure Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 234 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "max": 1, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 74, - "targets": [ - { - "expr": "evm_pool_rpc_node_num_transitions_to_alive{}", - "format": "", - "legendFormat": "Alive", - "refId": "" - }, - { - "expr": "evm_pool_rpc_node_num_transitions_to_in_sync{}", - "format": "", - "legendFormat": "InSync", - "refId": "" - }, - { - "expr": "evm_pool_rpc_node_num_transitions_to_out_of_sync{}", - "format": "", - "legendFormat": "OutOfSync", - "refId": "" - }, - { - "expr": "evm_pool_rpc_node_num_transitions_to_unreachable{}", - "format": "", - "legendFormat": "UnReachable", - "refId": "" - }, - { - "expr": "evm_pool_rpc_node_num_transitions_to_invalid_chain_id{}", - "format": "", - "legendFormat": "InvalidChainID", - "refId": "" - }, - { - "expr": "evm_pool_rpc_node_num_transitions_to_unusable{}", - "format": "", - "legendFormat": "TransitionToUnusable", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Transitions", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 240 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 75, - "targets": [ - { - "expr": "evm_pool_rpc_node_states{}", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{state}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node States", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 240 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 76, - "targets": [ - { - "expr": "sum(increase(evm_pool_rpc_node_verifies_success{}[$__rate_interval])) by (instance, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_verifies{}[$__rate_interval])) by (instance, evmChainID, nodeName) * 100", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{nodeName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Verifies Success Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 246 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 77, - "targets": [ - { - "expr": "sum(increase(evm_pool_rpc_node_verifies_failed{}[$__rate_interval])) by (instance, evmChainID, nodeName) / sum(increase(evm_pool_rpc_node_verifies{}[$__rate_interval])) by (instance, evmChainID, nodeName) * 100", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{nodeName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Verifies Failure Rate", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 246 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "EVM Pool RPC Node Latencies (App)", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 252 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 78, - "targets": [ - { - "expr": "histogram_quantile(0.90, sum(rate(evm_pool_rpc_node_rpc_call_time_bucket{}[$__rate_interval])) by (instance, le, rpcCallName)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{rpcCallName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Calls Latency 0.90 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 253 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 79, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(evm_pool_rpc_node_rpc_call_time_bucket{}[$__rate_interval])) by (instance, le, rpcCallName)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{rpcCallName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Calls Latency 0.95 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 259 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 80, - "targets": [ - { - "expr": "histogram_quantile(0.99, sum(rate(evm_pool_rpc_node_rpc_call_time_bucket{}[$__rate_interval])) by (instance, le, rpcCallName)) / 1e6", - "format": "", - "legendFormat": "{{instance}} - {{rpcCallName}}", - "refId": "" - } - ], - "title": "EVM Pool RPC Node Calls Latency 0.99 quantile", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 265 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ms", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Block History Estimator", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 271 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 81, - "targets": [ - { - "expr": "sum(gas_updater_all_gas_price_percentiles{}) by (instance, evmChainID, percentile)", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{percentile}}", - "refId": "" - } - ], - "title": "Gas Updater All Gas Price Percentiles", - "description": "Gas price at given percentile", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 272 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "gwei", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 82, - "targets": [ - { - "expr": "sum(gas_updater_all_tip_cap_percentiles{}) by (instance, evmChainID, percentile)", - "format": "", - "legendFormat": "{{instance}} - {{evmChainID}} - {{percentile}}", - "refId": "" - } - ], - "title": "Gas Updater All Tip Cap Percentiles", - "description": "Tip cap at given percentile", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 278 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "right", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 83, - "targets": [ - { - "expr": "sum(gas_updater_set_gas_price{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Gas Updater Set Gas Price", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 284 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 84, - "targets": [ - { - "expr": "sum(gas_updater_set_tip_cap{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Gas Updater Set Tip Cap", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 284 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 85, - "targets": [ - { - "expr": "sum(gas_updater_current_base_fee{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Gas Updater Current Base Fee", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 290 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 86, - "targets": [ - { - "expr": "sum(block_history_estimator_connectivity_failure_count{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Block History Estimator Connectivity Failure Count", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 290 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Pipeline Metrics (Runner)", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 296 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 87, - "targets": [ - { - "expr": "pipeline_task_execution_time{} / 1e6", - "format": "", - "legendFormat": "{{instance}} JobID: {{job_id}}", - "refId": "" - } - ], - "title": "Pipeline Task Execution Time", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 297 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "s", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 88, - "targets": [ - { - "expr": "pipeline_run_errors{}", - "format": "", - "legendFormat": "{{instance}} JobID: {{job_id}}", - "refId": "" - } - ], - "title": "Pipeline Run Errors", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 303 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 89, - "targets": [ - { - "expr": "pipeline_run_total_time_to_completion{} / 1e6", - "format": "", - "legendFormat": "{{instance}} JobID: {{job_id}}", - "refId": "" - } - ], - "title": "Pipeline Run Total Time to Completion", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 309 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "s", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 90, - "targets": [ - { - "expr": "pipeline_tasks_total_finished{}", - "format": "", - "legendFormat": "{{instance}} JobID: {{job_id}}", - "refId": "" - } - ], - "title": "Pipeline Tasks Total Finished", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 315 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "HTTP API", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 321 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 91, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(service_gonic_request_duration_bucket{}[$__rate_interval])) by (instance, le, path, method))", - "format": "", - "legendFormat": "{{instance}} - {{method}} - {{path}}", - "refId": "" - } - ], - "title": "Request Duration p95", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 322 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "s", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 92, - "targets": [ - { - "expr": "sum(rate(service_gonic_requests_total{}[$__rate_interval])) by (instance, path, method, code)", - "format": "", - "legendFormat": "{{instance}} - {{method}} - {{path}} - {{code}}", - "refId": "" - } - ], - "title": "Request Total Rate over interval", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 328 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 93, - "targets": [ - { - "expr": "avg(rate(service_gonic_request_size_bytes_sum{}[$__rate_interval])) by (instance)/avg(rate(service_gonic_request_size_bytes_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Average Request Size", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 334 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 94, - "targets": [ - { - "expr": "avg(rate(service_gonic_response_size_bytes_sum{}[$__rate_interval])) by (instance)/avg(rate(service_gonic_response_size_bytes_count{}[$__rate_interval])) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Response Size", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 334 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "PromHTTP", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 340 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 95, - "targets": [ - { - "expr": "sum(rate(promhttp_metric_handler_requests_total{}[$__rate_interval])) by (instance, code)", - "format": "", - "legendFormat": "{{instance}} - {{code}}", - "refId": "" - } - ], - "title": "HTTP rate by return code", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 341 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Go Metrics", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 347 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 96, - "targets": [ - { - "expr": "sum(go_threads{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Threads", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 348 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 97, - "targets": [ - { - "expr": "sum(go_memstats_heap_alloc_bytes{}) by (instance)", - "format": "", - "legendFormat": "", - "refId": "" - } - ], - "title": "Heap Allocations Stats", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 354 - }, - "options": { - "graphMode": "none", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 98, - "targets": [ - { - "expr": "sum(go_memstats_heap_alloc_bytes{}) by (instance)", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Heap allocations Graph", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 360 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 99, - "targets": [ - { - "expr": "go_memstats_heap_alloc_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Alloc", - "refId": "" - }, - { - "expr": "go_memstats_heap_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Sys", - "refId": "" - }, - { - "expr": "go_memstats_heap_idle_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Idle", - "refId": "" - }, - { - "expr": "go_memstats_heap_inuse_bytes{}", - "format": "", - "legendFormat": "{{instance}} - InUse", - "refId": "" - }, - { - "expr": "go_memstats_heap_released_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Released", - "refId": "" - } - ], - "title": "Heap Usage", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 366 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 100, - "targets": [ - { - "expr": "go_memstats_mspan_inuse_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Total InUse", - "refId": "" - }, - { - "expr": "go_memstats_mspan_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Total Sys", - "refId": "" - }, - { - "expr": "go_memstats_mcache_inuse_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Cache InUse", - "refId": "" - }, - { - "expr": "go_memstats_mcache_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Cache Sys", - "refId": "" - }, - { - "expr": "go_memstats_buck_hash_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Hash Sys", - "refId": "" - }, - { - "expr": "go_memstats_gc_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - GC Sys", - "refId": "" - }, - { - "expr": "go_memstats_other_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - bytes of memory are used for other runtime allocations", - "refId": "" - }, - { - "expr": "go_memstats_next_gc_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Next GC", - "refId": "" - } - ], - "title": "Memory in Off-Heap", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 366 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 101, - "targets": [ - { - "expr": "go_memstats_stack_inuse_bytes{}", - "format": "", - "legendFormat": "{{instance}} - InUse", - "refId": "" - }, - { - "expr": "go_memstats_stack_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}} - Sys", - "refId": "" - } - ], - "title": "Memory in Stack", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 372 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 102, - "targets": [ - { - "expr": "go_memstats_sys_bytes{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Total Used Memory", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 372 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 103, - "targets": [ - { - "expr": "go_memstats_mallocs_total{} - go_memstats_frees_total{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Number of Live Objects", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 378 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 104, - "targets": [ - { - "expr": "rate(go_memstats_mallocs_total{}[1m])", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Rate of Objects Allocated", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 378 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 105, - "targets": [ - { - "expr": "rate(go_memstats_lookups_total{}[1m])", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Rate of a Pointer Dereferences", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 384 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ops", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 106, - "targets": [ - { - "expr": "go_goroutines{}", - "format": "", - "legendFormat": "{{instance}}", - "refId": "" - } - ], - "title": "Goroutines", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 384 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "ops", - "decimals": 1, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "query", - "name": "instance", - "label": "Instance", - "description": "", - "query": "label_values(instance)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": true, - "sort": 1, - "includeAll": true - } - ] - }, - "annotations": {} - }, - "Alerts": [ - { - "annotations": { - "description": "Component {{ index $labels \"service_id\" }} uptime in the last 15m is {{ index $values \"C\" }}%", - "panel_title": "Health Avg by Service over 15m", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "Uptime less than 90% over last 15 minutes on one component in a Node" - }, - "condition": "D", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "health{}", - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "reducer": "mean", - "refId": "B", - "type": "reduce" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "$B * 100", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "C", - "type": "math" - }, - "refId": "C", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 90, - 0 - ], - "type": "lt" - } - } - ], - "expression": "C", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "D", - "type": "threshold" - }, - "refId": "D", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "15m", - "labels": { - "severity": "info" - }, - "noDataState": "NoData", - "orgID": 0, - "ruleGroup": "", - "title": "Health Avg by Service is less than 90%" - }, - { - "annotations": { - "description": "Component {{ index $labels \"service_id\" }} uptime in the last 15m is {{ index $values \"C\" }}%", - "panel_title": "Health Avg by Service over 15m", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "Uptime less than 70% over last 15 minutes on one component in a Node" - }, - "condition": "D", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "health{}", - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "reducer": "mean", - "refId": "B", - "type": "reduce" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "$B * 100", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "C", - "type": "math" - }, - "refId": "C", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 70, - 0 - ], - "type": "lt" - } - } - ], - "expression": "C", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "D", - "type": "threshold" - }, - "refId": "D", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "15m", - "labels": { - "severity": "warning" - }, - "noDataState": "NoData", - "orgID": 0, - "ruleGroup": "", - "title": "Health Avg by Service is less than 70%" - }, - { - "annotations": { - "description": "Component {{ index $labels \"service_id\" }} uptime in the last 15m is {{ index $values \"C\" }}%", - "panel_title": "Health Avg by Service over 15m", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "Uptime less than 50% over last 15 minutes on one component in a Node" - }, - "condition": "D", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "health{}", - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "reducer": "mean", - "refId": "B", - "type": "reduce" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "expression": "$B * 100", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "C", - "type": "math" - }, - "refId": "C", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 50, - 0 - ], - "type": "lt" - } - } - ], - "expression": "C", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "D", - "type": "threshold" - }, - "refId": "D", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "15m", - "labels": { - "severity": "critical" - }, - "noDataState": "NoData", - "orgID": 0, - "ruleGroup": "", - "title": "Health Avg by Service is less than 50%" - }, - { - "annotations": { - "description": "ETH Balance critically low at {{ index $values \"A\" }} on {{ index $labels \"instance\" }}", - "panel_title": "ETH Balance", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "ETH Balance is lower than threshold" - }, - "condition": "B", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "eth_balance{}", - "instant": true, - "range": false, - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 1, - 0 - ], - "type": "lt" - } - } - ], - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "B", - "type": "threshold" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "15m", - "labels": { - "severity": "critical" - }, - "noDataState": "OK", - "orgID": 0, - "ruleGroup": "", - "title": "ETH Balance" - }, - { - "annotations": { - "description": "Solana Balance critically low at {{ index $values \"A\" }} on {{ index $labels \"instance\" }}", - "panel_title": "SOL Balance", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "Solana Balance is lower than threshold" - }, - "condition": "B", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "solana_balance{}", - "instant": true, - "range": false, - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 1, - 0 - ], - "type": "lt" - } - } - ], - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "B", - "type": "threshold" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "15m", - "labels": { - "severity": "critical" - }, - "noDataState": "OK", - "orgID": 0, - "ruleGroup": "", - "title": "SOL Balance" - }, - { - "annotations": { - "description": "{{ index $labels \"instance\" }} on ChainID {{ index $labels \"ChainID\" }} has received {{ index $values \"A\" }} heads over 10 minutes.", - "panel_title": "Head Tracker Heads Received Rate", - "runbook_url": "https://github.com/smartcontractkit/chainlink-common/tree/main/observability-lib", - "summary": "No Headers Received" - }, - "condition": "B", - "data": [ - { - "datasourceUid": "1", - "model": { - "expr": "increase(head_tracker_heads_received{}[10m])", - "instant": true, - "range": false, - "legendFormat": "__auto", - "refId": "A" - }, - "refId": "A", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - }, - { - "datasourceUid": "__expr__", - "model": { - "conditions": [ - { - "evaluator": { - "params": [ - 1, - 0 - ], - "type": "lt" - } - } - ], - "expression": "A", - "intervalMs": 1000, - "maxDataPoints": 43200, - "refId": "B", - "type": "threshold" - }, - "refId": "B", - "relativeTimeRange": { - "from": 600, - "to": 0 - } - } - ], - "execErrState": "Alerting", - "folderUID": "", - "for": "10m", - "labels": { - "severity": "critical" - }, - "noDataState": "OK", - "orgID": 0, - "ruleGroup": "", - "title": "Head Tracker Heads Received Rate" - } - ], - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/dashboards/k8s-resources/component.go b/observability-lib/dashboards/k8s-resources/component.go deleted file mode 100644 index 2e3b19d9e..000000000 --- a/observability-lib/dashboards/k8s-resources/component.go +++ /dev/null @@ -1,416 +0,0 @@ -package k8sresources - -import ( - "fmt" - - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/common" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type Props struct { - Name string // Name is the name of the dashboard - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics -} - -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"Core", "Node", "Kubernetes", "Resources"}, - Refresh: "30s", - TimeFrom: "now-30m", - TimeTo: "now", - }) - - builder.AddVars(vars(props)...) - - builder.AddRow("Headlines") - builder.AddPanel(headlines(props)...) - - builder.AddRow("Pod Status") - builder.AddPanel(podStatus(props)...) - - builder.AddRow("Resources Usage") - builder.AddPanel(resourcesUsage(props)...) - - builder.AddRow("Network Usage") - builder.AddPanel(networkUsage(props)...) - - builder.AddRow("Disk Usage") - builder.AddPanel(diskUsage(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Environment", - Name: "env", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up, env)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Cluster", - Name: "cluster", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env"}, cluster)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Namespace", - Name: "namespace", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster"}, namespace)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Job", - Name: "job", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", namespace="$namespace"}, job)`, - Multi: false, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Pod", - Name: "pod", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(up{env="$env", cluster="$cluster", namespace="$namespace", job="$job"}, pod)`, - Multi: false, - })) - - return variables -} - -func headlines(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Utilisation (from requests)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: "{{pod}}", - Instant: true, - }, - }, - }, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Utilisation (from limits)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: "{{pod}}", - Instant: true, - }, - }, - }, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Utilisation (from requests)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", cluster="$cluster", namespace="$namespace", pod="$pod", image!=""}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: "{{pod}}", - Instant: true, - }, - }, - }, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Utilisation (from limits)", - Span: 6, - Height: 4, - Decimals: 1, - Unit: "percent", - Query: []grafana.Query{ - { - Expr: `100 * sum(container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", cluster="$cluster", namespace="$namespace", pod="$pod", container!="", image!=""}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster="$cluster", namespace="$namespace", pod="$pod"}) by (container)`, - Legend: "{{pod}}", - Instant: true, - }, - }, - }, - Orientation: common.VizOrientationHorizontal, - })) - - return panels -} - -func podStatus(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Pod Restarts", - Description: "Number of pod restarts", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `sum(increase(kube_pod_container_status_restarts_total{pod=~"$pod", namespace=~"${namespace}"}[$__rate_interval])) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "OOM Events", - Description: "Out-of-memory number of events", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `sum(container_oom_events_total{pod=~"$pod", namespace=~"${namespace}"}) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "OOM Killed", - Span: 8, - Height: 4, - Query: []grafana.Query{ - { - Expr: `kube_pod_container_status_last_terminated_reason{reason="OOMKilled", pod=~"$pod", namespace=~"${namespace}"}`, - Legend: "{{pod}}", - }, - }, - }, - ColorMode: common.BigValueColorModeNone, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - Orientation: common.VizOrientationHorizontal, - })) - - return panels -} - -func resourcesUsage(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "CPU Usage", - Span: 12, - Height: 6, - Decimals: 3, - Query: []grafana.Query{ - { - Expr: `sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{pod=~"$pod", namespace=~"${namespace}"}) by (pod)`, - Legend: "{{pod}}", - }, - { - Expr: `sum(kube_pod_container_resource_requests{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="cpu"})`, - Legend: "Requests", - }, - { - Expr: `sum(kube_pod_container_resource_limits{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="cpu"})`, - Legend: "Limits", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Memory Usage", - Span: 12, - Height: 6, - Unit: "bytes", - Query: []grafana.Query{ - { - Expr: `sum(container_memory_rss{pod=~"$pod", namespace=~"${namespace}", container!=""}) by (pod)`, - Legend: "{{pod}}", - }, - { - Expr: `sum(kube_pod_container_resource_requests{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="memory"})`, - Legend: "Requests", - }, - { - Expr: `sum(kube_pod_container_resource_limits{job="kube-state-metrics", cluster="$cluster", namespace="$namespace", pod="$pod", resource="memory"})`, - Legend: "Limits", - }, - }, - }, - })) - - return panels -} - -func networkUsage(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Receive Bandwidth", - Span: 12, - Height: 6, - Unit: "bps", - Query: []grafana.Query{ - { - Expr: `sum(irate(container_network_receive_bytes_total{pod=~"$pod", namespace=~"${namespace}"}[$__rate_interval])) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Transmit Bandwidth", - Span: 12, - Height: 6, - Unit: "bps", - Query: []grafana.Query{ - { - Expr: `sum(irate(container_network_transmit_bytes_total{pod=~"$pod", namespace=~"${namespace}"}[$__rate_interval])) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Average Container Bandwidth: Received", - Span: 12, - Height: 6, - Unit: "bps", - Query: []grafana.Query{ - { - Expr: `avg(irate(container_network_receive_bytes_total{pod=~"$pod", namespace=~"${namespace}"}[$__rate_interval])) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Average Container Bandwidth: Transmitted", - Span: 12, - Height: 6, - Unit: "bps", - Query: []grafana.Query{ - { - Expr: `avg(irate(container_network_transmit_bytes_total{pod=~"$pod", namespace=~"${namespace}"}[$__rate_interval])) by (pod)`, - Legend: "{{pod}}", - }, - }, - }, - })) - - return panels -} - -func diskUsage(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "IOPS(Read+Write)", - Span: 12, - Height: 6, - Decimals: 2, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `ceil(sum by(container, pod) (rate(container_fs_reads_total{job="kubelet", metrics_path="/metrics/cadvisor", container!="", cluster="$cluster", namespace="$namespace", pod="$pod"}[$__rate_interval]) + rate(container_fs_writes_total{job="kubelet", metrics_path="/metrics/cadvisor", container!="", cluster="$cluster", namespace="$namespace", pod="$pod"}[$__rate_interval])))`, - Legend: "{{pod}}", - }, - }, - }, - })) - - panels = append(panels, grafana.NewTimeSeriesPanel(&grafana.TimeSeriesPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "ThroughPut(Read+Write)", - Span: 12, - Height: 6, - Decimals: 2, - Unit: "short", - Query: []grafana.Query{ - { - Expr: `sum by(container, pod) (rate(container_fs_reads_bytes_total{job="kubelet", metrics_path="/metrics/cadvisor", container!="", cluster="$cluster", namespace="$namespace", pod="$pod"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job="kubelet", metrics_path="/metrics/cadvisor", container!="", cluster="$cluster", namespace="$namespace", pod="$pod"}[$__rate_interval]))`, - Legend: "{{pod}}", - }, - }, - }, - })) - - return panels -} diff --git a/observability-lib/dashboards/k8s-resources/component_test.go b/observability-lib/dashboards/k8s-resources/component_test.go deleted file mode 100644 index a32c7cda6..000000000 --- a/observability-lib/dashboards/k8s-resources/component_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package k8sresources_test - -import ( - "flag" - "os" - "testing" - - k8sresources "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/k8s-resources" - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - "github.com/stretchr/testify/require" -) - -var update = flag.Bool("update", false, "update golden test files") -var fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := k8sresources.NewDashboard(&k8sresources.Props{ - Name: "K8s resources", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := k8sresources.NewDashboard(&k8sresources.Props{ - Name: "K8s resources", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "K8s resources", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/k8s-resources/test-output.json b/observability-lib/dashboards/k8s-resources/test-output.json deleted file mode 100644 index 2a38e07e3..000000000 --- a/observability-lib/dashboards/k8s-resources/test-output.json +++ /dev/null @@ -1,990 +0,0 @@ -{ - "Dashboard": { - "title": "K8s resources", - "tags": [ - "Core", - "Node", - "Kubernetes", - "Resources" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-30m", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "row", - "collapsed": false, - "title": "Headlines", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 1, - "targets": [ - { - "expr": "100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "CPU Utilisation (from requests)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 2, - "targets": [ - { - "expr": "100 * sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "CPU Utilisation (from limits)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 3, - "targets": [ - { - "expr": "100 * sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Memory Utilisation (from requests)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 4, - "targets": [ - { - "expr": "100 * sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", - "instant": true, - "range": false, - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Memory Utilisation (from limits)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 1 - }, - "options": { - "graphMode": "none", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "percent", - "decimals": 1, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Pod Status", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 5 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 5, - "targets": [ - { - "expr": "sum(increase(kube_pod_container_status_restarts_total{pod=~\"$pod\", namespace=~\"${namespace}\"}[$__rate_interval])) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Pod Restarts", - "description": "Number of pod restarts", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 0, - "y": 6 - }, - "options": { - "graphMode": "line", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 6, - "targets": [ - { - "expr": "sum(container_oom_events_total{pod=~\"$pod\", namespace=~\"${namespace}\"}) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "OOM Events", - "description": "Out-of-memory number of events", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 8, - "y": 6 - }, - "options": { - "graphMode": "line", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 7, - "targets": [ - { - "expr": "kube_pod_container_status_last_terminated_reason{reason=\"OOMKilled\", pod=~\"$pod\", namespace=~\"${namespace}\"}", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "OOM Killed", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 4, - "w": 8, - "x": 16, - "y": 6 - }, - "options": { - "graphMode": "line", - "colorMode": "none", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "horizontal" - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 0, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Resources Usage", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 10 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 8, - "targets": [ - { - "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{pod=~\"$pod\", namespace=~\"${namespace}\"}) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - }, - { - "expr": "sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"})", - "format": "", - "legendFormat": "Requests", - "refId": "" - }, - { - "expr": "sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"})", - "format": "", - "legendFormat": "Limits", - "refId": "" - } - ], - "title": "CPU Usage", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 11 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "", - "decimals": 3, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 9, - "targets": [ - { - "expr": "sum(container_memory_rss{pod=~\"$pod\", namespace=~\"${namespace}\", container!=\"\"}) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - }, - { - "expr": "sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"})", - "format": "", - "legendFormat": "Requests", - "refId": "" - }, - { - "expr": "sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"})", - "format": "", - "legendFormat": "Limits", - "refId": "" - } - ], - "title": "Memory Usage", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 11 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bytes", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Network Usage", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 17 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 10, - "targets": [ - { - "expr": "sum(irate(container_network_receive_bytes_total{pod=~\"$pod\", namespace=~\"${namespace}\"}[$__rate_interval])) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Receive Bandwidth", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 18 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bps", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 11, - "targets": [ - { - "expr": "sum(irate(container_network_transmit_bytes_total{pod=~\"$pod\", namespace=~\"${namespace}\"}[$__rate_interval])) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Transmit Bandwidth", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 18 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bps", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 12, - "targets": [ - { - "expr": "avg(irate(container_network_receive_bytes_total{pod=~\"$pod\", namespace=~\"${namespace}\"}[$__rate_interval])) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Average Container Bandwidth: Received", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 24 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bps", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 13, - "targets": [ - { - "expr": "avg(irate(container_network_transmit_bytes_total{pod=~\"$pod\", namespace=~\"${namespace}\"}[$__rate_interval])) by (pod)", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "Average Container Bandwidth: Transmitted", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 24 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "bps", - "decimals": 0, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Disk Usage", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 30 - }, - "id": 0, - "panels": null - }, - { - "type": "timeseries", - "id": 14, - "targets": [ - { - "expr": "ceil(sum by(container, pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "IOPS(Read+Write)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 31 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - }, - { - "type": "timeseries", - "id": 15, - "targets": [ - { - "expr": "sum by(container, pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", - "format": "", - "legendFormat": "{{pod}}", - "refId": "" - } - ], - "title": "ThroughPut(Read+Write)", - "description": "", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 31 - }, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true, - "calcs": [] - }, - "tooltip": { - "mode": "", - "sort": "" - } - }, - "fieldConfig": { - "defaults": { - "unit": "short", - "decimals": 2, - "noValue": "No data", - "custom": { - "fillOpacity": 0, - "scaleDistribution": { - "type": "linear" - } - } - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "query", - "name": "env", - "label": "Environment", - "description": "", - "query": "label_values(up, env)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "cluster", - "label": "Cluster", - "description": "", - "query": "label_values(up{env=\"$env\"}, cluster)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "namespace", - "label": "Namespace", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\"}, namespace)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "job", - "label": "Job", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", namespace=\"$namespace\"}, job)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "pod", - "label": "Pod", - "description": "", - "query": "label_values(up{env=\"$env\", cluster=\"$cluster\", namespace=\"$namespace\", job=\"$job\"}, pod)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - } - ] - }, - "annotations": {} - }, - "Alerts": null, - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/dashboards/nop-ocr/component.go b/observability-lib/dashboards/nop-ocr/component.go deleted file mode 100644 index 9978c5f73..000000000 --- a/observability-lib/dashboards/nop-ocr/component.go +++ /dev/null @@ -1,352 +0,0 @@ -package nopocr - -import ( - "fmt" - - "github.com/grafana/grafana-foundation-sdk/go/cog" - "github.com/grafana/grafana-foundation-sdk/go/common" - "github.com/grafana/grafana-foundation-sdk/go/dashboard" - - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" -) - -type Props struct { - Name string // Name is the name of the dashboard - MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics - OCRVersion string // OCRVersion is the version of the OCR (ocr, ocr2, ocr3) -} - -func NewDashboard(props *Props) (*grafana.Observability, error) { - if props.Name == "" { - return nil, fmt.Errorf("Name is required") - } - - builder := grafana.NewBuilder(&grafana.BuilderOptions{ - Name: props.Name, - Tags: []string{"NOP", "Health", props.OCRVersion}, - Refresh: "30s", - TimeFrom: "now-1d", - TimeTo: "now", - }) - - builder.AddVars(vars(props)...) - - builder.AddRow("Per Contract") - builder.AddPanel(perContract(props)...) - - builder.AddRow("Per NOP") - builder.AddPanel(perNOP(props)...) - - return builder.Build() -} - -func vars(p *Props) []cog.Builder[dashboard.VariableModel] { - var variables []cog.Builder[dashboard.VariableModel] - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Environment", - Name: "env", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(` + p.OCRVersion + `_contract_config_f{}, env)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "Contract", - Name: "contract", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(` + p.OCRVersion + `_contract_oracle_active{env="$env"}, contract)`, - })) - - variables = append(variables, grafana.NewQueryVariable(&grafana.QueryVariableOptions{ - VariableOption: &grafana.VariableOption{ - Label: "NOP", - Name: "oracle", - }, - Datasource: p.MetricsDataSource.Name, - Query: `label_values(` + p.OCRVersion + `_contract_oracle_active{env="$env"}, oracle)`, - })) - - return variables -} - -func perContract(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Rounds Epoch Progression", - Description: "Rounds have stopped progressing for 90 seconds means NOP is unhealthy", - Span: 24, - Height: 10, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_epoch_round{env=~"${env}", contract=~"${contract}"}[90s])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{oracle}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Message Observe", - Description: "NOP have stopped sending messages for 3mins means NOP is unhealthy", - Span: 24, - Height: 10, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_message_observe_total{env=~"${env}", contract=~"${contract}"}[3m])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{oracle}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Observations included in report", - Description: "NOP observations were not including in report for 3mins means NOP is unhealthy", - Span: 24, - Height: 10, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_message_report_req_observation_total{env=~"${env}", contract=~"${contract}"}[3m])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{oracle}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - return panels -} - -func perNOP(p *Props) []*grafana.Panel { - var panels []*grafana.Panel - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Rounds Epoch Progression", - Description: "Rounds have stopped progressing for 5mins means NOP is unhealthy", - Span: 24, - Height: 32, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_epoch_round{env=~"${env}", oracle=~"${oracle}"}[90s])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{contract}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Message Observe", - Description: "NOP have stopped sending messages for 3mins means NOP is unhealthy", - Span: 24, - Height: 32, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_message_observe_total{env=~"${env}", oracle=~"${oracle}"}[3m])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{contract}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "Observations included in report", - Description: "NOP observations were not including in report for 3mins means NOP is unhealthy", - Span: 24, - Height: 32, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_message_report_req_observation_total{env=~"${env}", oracle=~"${oracle}"}[3m])) by (env, contract, feed_id, network_name, oracle) >bool 0)[$__range:])`, - Legend: `{{contract}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - panels = append(panels, grafana.NewStatPanel(&grafana.StatPanelOptions{ - PanelOptions: &grafana.PanelOptions{ - Datasource: p.MetricsDataSource.Name, - Title: "P2P Connectivity", - Description: "Connectivity got interrupted for 60 seconds received from other nodes", - Span: 24, - Height: 32, - Decimals: 2, - Unit: "percentunit", - Query: []grafana.Query{ - { - Expr: `avg_over_time((sum(changes(` + p.OCRVersion + `_telemetry_p2p_received_total{env=~"${env}", receiver=~"${oracle}"}[3m])) by (sender, receiver) >bool 0)[$__range:])`, - Legend: `{{receiver}} < {{sender}}`, - }, - }, - Threshold: &grafana.ThresholdOptions{ - Mode: dashboard.ThresholdsModeAbsolute, - Steps: []dashboard.Threshold{ - {Value: nil, Color: "default"}, - {Value: grafana.Pointer[float64](0), Color: "red"}, - {Value: grafana.Pointer[float64](0.80), Color: "orange"}, - {Value: grafana.Pointer[float64](0.99), Color: "green"}, - }, - }, - Transform: &grafana.TransformOptions{ - ID: "renameByRegex", - Options: map[string]string{ - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "", - }, - }, - }, - TextSize: 10, - ValueSize: 18, - GraphMode: common.BigValueGraphModeLine, - TextMode: common.BigValueTextModeValueAndName, - })) - - return panels -} diff --git a/observability-lib/dashboards/nop-ocr/component_test.go b/observability-lib/dashboards/nop-ocr/component_test.go deleted file mode 100644 index cfa4009a3..000000000 --- a/observability-lib/dashboards/nop-ocr/component_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package nopocr_test - -import ( - "flag" - "os" - "testing" - - nopocr "github.com/smartcontractkit/chainlink-common/observability-lib/dashboards/nop-ocr" - "github.com/smartcontractkit/chainlink-common/observability-lib/grafana" - - "github.com/stretchr/testify/require" -) - -var update = flag.Bool("update", false, "update golden test files") - -const fileOutput = "test-output.json" - -func TestGenerateFile(t *testing.T) { - if *update == false { - t.Skip("skipping test") - } - - testDashboard, err := nopocr.NewDashboard(&nopocr.Props{ - Name: "NOP OCR Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - if _, errExists := os.Stat(fileOutput); errExists == nil { - errRemove := os.Remove(fileOutput) - if errRemove != nil { - t.Errorf("Error removing file: %v", errRemove) - } - } - file, errFile := os.Create(fileOutput) - if errFile != nil { - panic(errFile) - } - writeString, err := file.WriteString(string(json)) - if err != nil { - t.Errorf("Error writing to file: %v", writeString) - } - t.Cleanup(func() { - file.Close() - }) -} - -func TestNewDashboard(t *testing.T) { - t.Run("NewDashboard creates a dashboard", func(t *testing.T) { - testDashboard, err := nopocr.NewDashboard(&nopocr.Props{ - Name: "NOP OCR Dashboard", - MetricsDataSource: grafana.NewDataSource("Prometheus", ""), - }) - if err != nil { - t.Errorf("Error creating dashboard: %v", err) - } - require.IsType(t, grafana.Observability{}, *testDashboard) - require.Equal(t, "NOP OCR Dashboard", *testDashboard.Dashboard.Title) - json, errJSON := testDashboard.GenerateJSON() - if errJSON != nil { - t.Errorf("Error generating JSON: %v", errJSON) - } - - jsonCompared, errCompared := os.ReadFile(fileOutput) - if errCompared != nil { - t.Errorf("Error reading file: %v", errCompared) - } - - require.JSONEq(t, string(jsonCompared), string(json)) - }) -} diff --git a/observability-lib/dashboards/nop-ocr/test-output.json b/observability-lib/dashboards/nop-ocr/test-output.json deleted file mode 100644 index 006074e65..000000000 --- a/observability-lib/dashboards/nop-ocr/test-output.json +++ /dev/null @@ -1,686 +0,0 @@ -{ - "Dashboard": { - "title": "NOP OCR Dashboard", - "tags": [ - "NOP", - "Health", - "" - ], - "timezone": "browser", - "editable": true, - "graphTooltip": 0, - "time": { - "from": "now-1d", - "to": "now" - }, - "fiscalYearStartMonth": 0, - "refresh": "30s", - "schemaVersion": 39, - "panels": [ - { - "type": "row", - "collapsed": false, - "title": "Per Contract", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 1, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_epoch_round{env=~\"${env}\", contract=~\"${contract}\"}[90s])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Rounds Epoch Progression", - "description": "Rounds have stopped progressing for 90 seconds means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 1 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 2, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_message_observe_total{env=~\"${env}\", contract=~\"${contract}\"}[3m])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Message Observe", - "description": "NOP have stopped sending messages for 3mins means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 11 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 3, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_message_report_req_observation_total{env=~\"${env}\", contract=~\"${contract}\"}[3m])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{oracle}}", - "refId": "" - } - ], - "title": "Observations included in report", - "description": "NOP observations were not including in report for 3mins means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 21 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "row", - "collapsed": false, - "title": "Per NOP", - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 31 - }, - "id": 0, - "panels": null - }, - { - "type": "stat", - "id": 4, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_epoch_round{env=~\"${env}\", oracle=~\"${oracle}\"}[90s])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Rounds Epoch Progression", - "description": "Rounds have stopped progressing for 5mins means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 32, - "w": 24, - "x": 0, - "y": 32 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 5, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_message_observe_total{env=~\"${env}\", oracle=~\"${oracle}\"}[3m])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Message Observe", - "description": "NOP have stopped sending messages for 3mins means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 32, - "w": 24, - "x": 0, - "y": 64 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 6, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_message_report_req_observation_total{env=~\"${env}\", oracle=~\"${oracle}\"}[3m])) by (env, contract, feed_id, network_name, oracle) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{contract}}", - "refId": "" - } - ], - "title": "Observations included in report", - "description": "NOP observations were not including in report for 3mins means NOP is unhealthy", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 32, - "w": 24, - "x": 0, - "y": 96 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - }, - { - "type": "stat", - "id": 7, - "targets": [ - { - "expr": "avg_over_time((sum(changes(_telemetry_p2p_received_total{env=~\"${env}\", receiver=~\"${oracle}\"}[3m])) by (sender, receiver) \u003ebool 0)[$__range:])", - "format": "", - "legendFormat": "{{receiver}} \u003c {{sender}}", - "refId": "" - } - ], - "title": "P2P Connectivity", - "description": "Connectivity got interrupted for 60 seconds received from other nodes", - "transparent": false, - "datasource": { - "uid": "Prometheus" - }, - "gridPos": { - "h": 32, - "w": 24, - "x": 0, - "y": 128 - }, - "transformations": [ - { - "id": "renameByRegex", - "options": { - "regex": "/^(.*[\\\\\\/])/", - "renamePattern": "" - } - } - ], - "options": { - "graphMode": "line", - "colorMode": "value", - "justifyMode": "auto", - "textMode": "value_and_name", - "wideLayout": true, - "showPercentChange": false, - "reduceOptions": { - "calcs": [ - "last" - ] - }, - "text": { - "titleSize": 10, - "valueSize": 18 - }, - "percentChangeColorMode": "standard", - "orientation": "auto" - }, - "fieldConfig": { - "defaults": { - "unit": "percentunit", - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "value": null, - "color": "default" - }, - { - "value": 0, - "color": "red" - }, - { - "value": 0.8, - "color": "orange" - }, - { - "value": 0.99, - "color": "green" - } - ] - }, - "noValue": "No data" - }, - "overrides": null - } - } - ], - "templating": { - "list": [ - { - "type": "query", - "name": "env", - "label": "Environment", - "description": "", - "query": "label_values(_contract_config_f{}, env)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "contract", - "label": "Contract", - "description": "", - "query": "label_values(_contract_oracle_active{env=\"$env\"}, contract)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - }, - { - "type": "query", - "name": "oracle", - "label": "NOP", - "description": "", - "query": "label_values(_contract_oracle_active{env=\"$env\"}, oracle)", - "datasource": { - "uid": "Prometheus" - }, - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "multi": false, - "sort": 1 - } - ] - }, - "annotations": {} - }, - "Alerts": null, - "ContactPoints": null, - "NotificationPolicies": null -} \ No newline at end of file diff --git a/observability-lib/go.mod b/observability-lib/go.mod index e03ce2f63..544957751 100644 --- a/observability-lib/go.mod +++ b/observability-lib/go.mod @@ -5,7 +5,6 @@ go 1.21.4 require ( github.com/go-resty/resty/v2 v2.15.3 github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241009194022-923b32e3e69b - github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v3 v3.0.1 @@ -15,12 +14,9 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/sys v0.26.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/observability-lib/go.sum b/observability-lib/go.sum index f59de2c33..02dadb6ce 100644 --- a/observability-lib/go.sum +++ b/observability-lib/go.sum @@ -1,11 +1,9 @@ -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8= github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241009194022-923b32e3e69b h1:YxlugK0wL5hh86wT0hZSGw9cPTvacOUmHxjP15fsIlE= github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241009194022-923b32e3e69b/go.mod h1:WtWosval1KCZP9BGa42b8aVoJmVXSg0EvQXi9LDSVZQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -17,22 +15,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= @@ -42,11 +30,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/observability-lib/grafana/alerts-group.go b/observability-lib/grafana/alerts-group.go new file mode 100644 index 000000000..e7f845a2f --- /dev/null +++ b/observability-lib/grafana/alerts-group.go @@ -0,0 +1,15 @@ +package grafana + +import ( + "github.com/grafana/grafana-foundation-sdk/go/alerting" +) + +type AlertGroupOptions struct { + Title string + Interval alerting.Duration // duration in seconds +} + +func NewAlertGroup(options *AlertGroupOptions) *alerting.RuleGroupBuilder { + return alerting.NewRuleGroupBuilder(options.Title). + Interval(options.Interval) +} diff --git a/observability-lib/grafana/alerts.go b/observability-lib/grafana/alerts.go index 980d3ac74..e812f857f 100644 --- a/observability-lib/grafana/alerts.go +++ b/observability-lib/grafana/alerts.go @@ -170,6 +170,7 @@ type AlertOptions struct { QueryRefCondition string Condition []ConditionQuery PanelTitle string + RuleGroupTitle string } func NewAlertRule(options *AlertOptions) *alerting.RuleBuilder { @@ -207,6 +208,10 @@ func NewAlertRule(options *AlertOptions) *alerting.RuleBuilder { Annotations(annotations). Labels(options.Tags) + if options.RuleGroupTitle != "" { + rule.RuleGroup(options.RuleGroupTitle) + } + for _, query := range options.Query { rule.WithQuery(newRuleQuery(query)) } diff --git a/observability-lib/grafana/builder.go b/observability-lib/grafana/builder.go index 10d5813c9..426d5cd5c 100644 --- a/observability-lib/grafana/builder.go +++ b/observability-lib/grafana/builder.go @@ -12,6 +12,7 @@ import ( type Builder struct { dashboardBuilder *dashboard.DashboardBuilder alertsBuilder []*alerting.RuleBuilder + alertGroupsBuilder []*alerting.RuleGroupBuilder contactPointsBuilder []*alerting.ContactPointBuilder notificationPoliciesBuilder []*alerting.NotificationPolicyBuilder panelCounter uint32 @@ -103,6 +104,10 @@ func (b *Builder) AddAlert(alerts ...*alerting.RuleBuilder) { b.alertsBuilder = append(b.alertsBuilder, alerts...) } +func (b *Builder) AddAlertGroup(alertGroups ...*alerting.RuleGroupBuilder) { + b.alertGroupsBuilder = append(b.alertGroupsBuilder, alertGroups...) +} + func (b *Builder) AddContactPoint(contactPoints ...*alerting.ContactPointBuilder) { b.contactPointsBuilder = append(b.contactPointsBuilder, contactPoints...) } @@ -120,31 +125,41 @@ func (b *Builder) Build() (*Observability, error) { return nil, errBuildDashboard } observability.Dashboard = &db + } - var alerts []alerting.Rule - for _, alertBuilder := range b.alertsBuilder { - alert, errBuildAlert := alertBuilder.Build() - if errBuildAlert != nil { - return nil, errBuildAlert - } + var alerts []alerting.Rule + for _, alertBuilder := range b.alertsBuilder { + alert, errBuildAlert := alertBuilder.Build() + if errBuildAlert != nil { + return nil, errBuildAlert + } - // Add common tags to alerts - if b.alertsTags != nil && len(b.alertsTags) > 0 { - tags := maps.Clone(b.alertsTags) - maps.Copy(tags, alert.Labels) - - alertBuildWithTags := alertBuilder.Labels(tags) - alertWithTags, errBuildAlertWithTags := alertBuildWithTags.Build() - if errBuildAlertWithTags != nil { - return nil, errBuildAlertWithTags - } - alerts = append(alerts, alertWithTags) - } else { - alerts = append(alerts, alert) + // Add common tags to alerts + if b.alertsTags != nil && len(b.alertsTags) > 0 { + tags := maps.Clone(b.alertsTags) + maps.Copy(tags, alert.Labels) + + alertBuildWithTags := alertBuilder.Labels(tags) + alertWithTags, errBuildAlertWithTags := alertBuildWithTags.Build() + if errBuildAlertWithTags != nil { + return nil, errBuildAlertWithTags } + alerts = append(alerts, alertWithTags) + } else { + alerts = append(alerts, alert) + } + } + observability.Alerts = alerts + + var alertGroups []alerting.RuleGroup + for _, alertGroupBuilder := range b.alertGroupsBuilder { + alertGroup, errBuildAlertGroup := alertGroupBuilder.Build() + if errBuildAlertGroup != nil { + return nil, errBuildAlertGroup } - observability.Alerts = alerts + alertGroups = append(alertGroups, alertGroup) } + observability.AlertGroups = alertGroups var contactPoints []alerting.ContactPoint for _, contactPointBuilder := range b.contactPointsBuilder { diff --git a/observability-lib/grafana/builder_test.go b/observability-lib/grafana/builder_test.go index e31db74de..2c4f56253 100644 --- a/observability-lib/grafana/builder_test.go +++ b/observability-lib/grafana/builder_test.go @@ -50,9 +50,44 @@ func TestNewBuilder(t *testing.T) { if err != nil { t.Errorf("Error during build: %v", err) } - require.NotEmpty(t, o.Dashboard) require.NotEmpty(t, o.Alerts) + require.Len(t, o.Alerts, 1) + require.Empty(t, o.ContactPoints) + require.Empty(t, o.NotificationPolicies) + }) + + t.Run("NewBuilder builds only alerts", func(t *testing.T) { + builder := grafana.NewBuilder(&grafana.BuilderOptions{}) + builder.AddAlert(grafana.NewAlertRule(&grafana.AlertOptions{ + Title: "Alert Title", + })) + + o, err := builder.Build() + if err != nil { + t.Errorf("Error during build: %v", err) + } + require.Empty(t, o.Dashboard) + require.NotEmpty(t, o.Alerts) + require.Len(t, o.Alerts, 1) + require.Empty(t, o.ContactPoints) + require.Empty(t, o.NotificationPolicies) + }) + + t.Run("NewBuilder builds an alert group", func(t *testing.T) { + builder := grafana.NewBuilder(&grafana.BuilderOptions{}) + builder.AddAlertGroup(grafana.NewAlertGroup(&grafana.AlertGroupOptions{ + Title: "Group Title", + Interval: 30, // duration in seconds + })) + + o, err := builder.Build() + if err != nil { + t.Errorf("Error during build: %v", err) + } + require.Empty(t, o.Dashboard) + require.NotEmpty(t, o.AlertGroups) + require.Len(t, o.AlertGroups, 1) require.Empty(t, o.ContactPoints) require.Empty(t, o.NotificationPolicies) }) diff --git a/observability-lib/grafana/dashboard.go b/observability-lib/grafana/dashboard.go index ece0fc963..303193705 100644 --- a/observability-lib/grafana/dashboard.go +++ b/observability-lib/grafana/dashboard.go @@ -20,6 +20,7 @@ const ( type Observability struct { Dashboard *dashboard.Dashboard Alerts []alerting.Rule + AlertGroups []alerting.RuleGroup ContactPoints []alerting.ContactPoint NotificationPolicies []alerting.NotificationPolicy } @@ -59,18 +60,51 @@ func getAlertRuleByTitle(alerts []alerting.Rule, title string) *alerting.Rule { return nil } +func getAlertRules(grafanaClient *api.Client, dashboardUID *string, folderUID string, alertGroups []alerting.RuleGroup) ([]alerting.Rule, error) { + var alertsRule []alerting.Rule + var errGetAlertRules error + + if dashboardUID != nil { + alertsRule, errGetAlertRules = grafanaClient.GetAlertRulesByDashboardUID(*dashboardUID) + if errGetAlertRules != nil { + return nil, errGetAlertRules + } + } else { + if alertGroups != nil && len(alertGroups) > 0 { + for _, alertGroup := range alertGroups { + alertsRulePerGroup, errGetAlertRulesPerGroup := grafanaClient.GetAlertRulesByFolderUIDAndGroupName(folderUID, *alertGroup.Title) + if errGetAlertRulesPerGroup != nil { + return nil, errGetAlertRulesPerGroup + } + alertsRule = append(alertsRule, alertsRulePerGroup...) + } + } + } + + return alertsRule, nil +} + func (o *Observability) DeployToGrafana(options *DeployOptions) error { grafanaClient := api.NewClient( options.GrafanaURL, options.GrafanaToken, ) + // Create or update folder + var folder *api.Folder + var errFolder error if options.FolderName != "" { - folder, errFolder := grafanaClient.FindOrCreateFolder(options.FolderName) + folder, errFolder = grafanaClient.FindOrCreateFolder(options.FolderName) if errFolder != nil { return errFolder } - newDashboard, _, errPostDashboard := grafanaClient.PostDashboard(api.PostDashboardRequest{ + } + + // Create or update dashboard + var newDashboard api.PostDashboardResponse + var errPostDashboard error + if folder != nil && o.Dashboard != nil { + newDashboard, _, errPostDashboard = grafanaClient.PostDashboard(api.PostDashboardRequest{ Dashboard: o.Dashboard, Overwrite: true, FolderID: int(folder.ID), @@ -78,16 +112,33 @@ func (o *Observability) DeployToGrafana(options *DeployOptions) error { if errPostDashboard != nil { return errPostDashboard } + } + + // If disabling alerts delete alerts for the folder and alert groups scope + if folder != nil && !options.EnableAlerts && o.Alerts != nil && len(o.Alerts) > 0 { + alertsRule, errGetAlertRules := getAlertRules(grafanaClient, newDashboard.UID, folder.UID, o.AlertGroups) + if errGetAlertRules != nil { + return errGetAlertRules + } - if !options.EnableAlerts && o.Alerts != nil && len(o.Alerts) > 0 { - // Get alert rules for the dashboard - alertsRule, errGetAlertRules := grafanaClient.GetAlertRulesByDashboardUID(*newDashboard.UID) - if errGetAlertRules != nil { - return errGetAlertRules + for _, rule := range alertsRule { + _, _, errDeleteAlertRule := grafanaClient.DeleteAlertRule(*rule.Uid) + if errDeleteAlertRule != nil { + return errDeleteAlertRule } + } + } - // delete existing alert rules for the dashboard if alerts are disabled - for _, rule := range alertsRule { + // Create or update alerts + if folder != nil && options.EnableAlerts && o.Alerts != nil && len(o.Alerts) > 0 { + alertsRule, errGetAlertRules := getAlertRules(grafanaClient, newDashboard.UID, folder.UID, o.AlertGroups) + if errGetAlertRules != nil { + return errGetAlertRules + } + + // delete alert rules that are not defined anymore in the code + for _, rule := range alertsRule { + if !alertRuleExist(o.Alerts, rule) { _, _, errDeleteAlertRule := grafanaClient.DeleteAlertRule(*rule.Uid) if errDeleteAlertRule != nil { return errDeleteAlertRule @@ -95,53 +146,56 @@ func (o *Observability) DeployToGrafana(options *DeployOptions) error { } } - // Create alerts for the dashboard - if options.EnableAlerts && o.Alerts != nil && len(o.Alerts) > 0 { - // Get alert rules for the dashboard - alertsRule, errGetAlertRules := grafanaClient.GetAlertRulesByDashboardUID(*newDashboard.UID) - if errGetAlertRules != nil { - return errGetAlertRules + // Create alert rules + for _, alert := range o.Alerts { + if folder.UID != "" { + alert.FolderUID = folder.UID } - - // delete alert rules for the dashboard - for _, rule := range alertsRule { - // delete alert rule only if it won't be created again from code - if !alertRuleExist(o.Alerts, rule) { - _, _, errDeleteAlertRule := grafanaClient.DeleteAlertRule(*rule.Uid) - if errDeleteAlertRule != nil { - return errDeleteAlertRule + if o.Dashboard != nil { + if alert.RuleGroup == "" { + alert.RuleGroup = *o.Dashboard.Title + } + if alert.Annotations["panel_title"] != "" { + panelId := panelIDByTitle(o.Dashboard, alert.Annotations["panel_title"]) + // we can clean it up as it was only used to get the panelId + delete(alert.Annotations, "panel_title") + if panelId != "" { + // Both or none should be set + alert.Annotations["__panelId__"] = panelId + alert.Annotations["__dashboardUid__"] = *newDashboard.UID } } + } else { + if alert.RuleGroup == "" { + return fmt.Errorf("you must create at one rule group and set it to your alerts") + } } - // Create alert rules for the dashboard - for _, alert := range o.Alerts { - alert.RuleGroup = *o.Dashboard.Title - alert.FolderUID = folder.UID - alert.Annotations["__dashboardUid__"] = *newDashboard.UID - - panelId := panelIDByTitle(o.Dashboard, alert.Annotations["panel_title"]) - // we can clean it up as it was only used to get the panelId - delete(alert.Annotations, "panel_title") - if panelId != "" { - alert.Annotations["__panelId__"] = panelId - } - if alertRuleExist(alertsRule, alert) { - // update alert rule if it already exists - alertToUpdate := getAlertRuleByTitle(alertsRule, alert.Title) - if alertToUpdate != nil { - _, _, errPutAlertRule := grafanaClient.UpdateAlertRule(*alertToUpdate.Uid, alert) - if errPutAlertRule != nil { - return errPutAlertRule - } - } - } else { - // create alert rule if it doesn't exist - _, _, errPostAlertRule := grafanaClient.PostAlertRule(alert) - if errPostAlertRule != nil { - return errPostAlertRule + if alertRuleExist(alertsRule, alert) { + // update alert rule if it already exists + alertToUpdate := getAlertRuleByTitle(alertsRule, alert.Title) + if alertToUpdate != nil { + _, _, errPutAlertRule := grafanaClient.UpdateAlertRule(*alertToUpdate.Uid, alert) + if errPutAlertRule != nil { + return errPutAlertRule } } + } else { + // create alert rule if it doesn't exist + _, _, errPostAlertRule := grafanaClient.PostAlertRule(alert) + if errPostAlertRule != nil { + return errPostAlertRule + } + } + } + } + + // Update alert groups + if folder != nil { + for _, alertGroup := range o.AlertGroups { + _, _, errPostAlertGroup := grafanaClient.UpdateAlertRuleGroup(folder.UID, alertGroup) + if errPostAlertGroup != nil { + return errPostAlertGroup } } } diff --git a/observability-lib/main.go b/observability-lib/main.go index 73a5d750d..0a1350eb7 100644 --- a/observability-lib/main.go +++ b/observability-lib/main.go @@ -1,26 +1,9 @@ package main import ( - "log" - - "github.com/spf13/cobra" - "github.com/smartcontractkit/chainlink-common/observability-lib/cmd" ) -var rootCmd = &cobra.Command{ - Use: "observability-lib", - Short: "observability-lib is a library for creating and deploying Grafana dashboards and alerts", -} - -func init() { - rootCmd.AddCommand(cmd.DeployCmd) - rootCmd.AddCommand(cmd.DeleteCmd) - rootCmd.AddCommand(cmd.GenerateCmd) -} - func main() { - if err := rootCmd.Execute(); err != nil { - log.Fatalln(err) - } + cmd.Execute() } diff --git a/pkg/beholder/client.go b/pkg/beholder/client.go index b4f64f650..c6bac815a 100644 --- a/pkg/beholder/client.go +++ b/pkg/beholder/client.go @@ -14,7 +14,6 @@ import ( sdklog "go.opentelemetry.io/otel/sdk/log" sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdkresource "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/credentials" @@ -112,9 +111,13 @@ func newGRPCClient(cfg Config, otlploggrpcNew otlploggrpcFactory) (*Client, erro // Logger var loggerProcessor sdklog.Processor if cfg.LogBatchProcessor { + batchProcessorOpts := []sdklog.BatchProcessorOption{} + if cfg.LogExportTimeout > 0 { + batchProcessorOpts = append(batchProcessorOpts, sdklog.WithExportTimeout(cfg.LogExportTimeout)) // Default is 30s + } loggerProcessor = sdklog.NewBatchProcessor( sharedLogExporter, - sdklog.WithExportTimeout(cfg.LogExportTimeout), // Default is 30s + batchProcessorOpts..., ) } else { loggerProcessor = sdklog.NewSimpleProcessor(sharedLogExporter) @@ -152,9 +155,13 @@ func newGRPCClient(cfg Config, otlploggrpcNew otlploggrpcFactory) (*Client, erro // Message Emitter var messageLogProcessor sdklog.Processor if cfg.EmitterBatchProcessor { + batchProcessorOpts := []sdklog.BatchProcessorOption{} + if cfg.EmitterExportTimeout > 0 { + batchProcessorOpts = append(batchProcessorOpts, sdklog.WithExportTimeout(cfg.EmitterExportTimeout)) // Default is 30s + } messageLogProcessor = sdklog.NewBatchProcessor( sharedLogExporter, - sdklog.WithExportTimeout(cfg.EmitterExportTimeout), // Default is 30s + batchProcessorOpts..., ) } else { messageLogProcessor = sdklog.NewSimpleProcessor(sharedLogExporter) @@ -314,9 +321,12 @@ func newTracerProvider(config Config, resource *sdkresource.Resource, creds cred if err != nil { return nil, err } - + batcherOpts := []sdktrace.BatchSpanProcessorOption{} + if config.TraceBatchTimeout > 0 { + batcherOpts = append(batcherOpts, sdktrace.WithBatchTimeout(config.TraceBatchTimeout)) // Default is 5s + } opts := []sdktrace.TracerProviderOption{ - sdktrace.WithBatcher(exporter, trace.WithBatchTimeout(config.TraceBatchTimeout)), // Default is 5s + sdktrace.WithBatcher(exporter, batcherOpts...), sdktrace.WithResource(resource), sdktrace.WithSampler( sdktrace.ParentBased( @@ -359,6 +369,7 @@ func newMeterProvider(config Config, resource *sdkresource.Resource, creds crede sdkmetric.WithInterval(config.MetricReaderInterval), // Default is 10s )), sdkmetric.WithResource(resource), + sdkmetric.WithView(config.MetricViews...), ) return mp, nil } diff --git a/pkg/beholder/config.go b/pkg/beholder/config.go index b99d20176..75255c891 100644 --- a/pkg/beholder/config.go +++ b/pkg/beholder/config.go @@ -4,6 +4,7 @@ import ( "time" otelattr "go.opentelemetry.io/otel/attribute" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -28,6 +29,7 @@ type Config struct { // OTel Metric MetricReaderInterval time.Duration MetricRetryConfig *RetryConfig + MetricViews []sdkmetric.View // OTel Log LogExportTimeout time.Duration // Batch processing is enabled by default diff --git a/pkg/beholder/config_test.go b/pkg/beholder/config_test.go index c1d2a42c0..538ad5d36 100644 --- a/pkg/beholder/config_test.go +++ b/pkg/beholder/config_test.go @@ -50,6 +50,6 @@ func ExampleConfig() { } fmt.Printf("%+v\n", *config.LogRetryConfig) // Output: - // {InsecureConnection:true CACertFile: OtelExporterGRPCEndpoint:localhost:4317 OtelExporterHTTPEndpoint:localhost:4318 ResourceAttributes:[{Key:package_name Value:{vtype:4 numeric:0 stringly:beholder slice:}} {Key:sender Value:{vtype:4 numeric:0 stringly:beholderclient slice:}}] EmitterExportTimeout:1s EmitterBatchProcessor:true TraceSampleRatio:1 TraceBatchTimeout:1s TraceSpanExporter: TraceRetryConfig: MetricReaderInterval:1s MetricRetryConfig: LogExportTimeout:1s LogBatchProcessor:true LogRetryConfig: AuthPublicKeyHex: AuthHeaders:map[]} + // {InsecureConnection:true CACertFile: OtelExporterGRPCEndpoint:localhost:4317 OtelExporterHTTPEndpoint:localhost:4318 ResourceAttributes:[{Key:package_name Value:{vtype:4 numeric:0 stringly:beholder slice:}} {Key:sender Value:{vtype:4 numeric:0 stringly:beholderclient slice:}}] EmitterExportTimeout:1s EmitterBatchProcessor:true TraceSampleRatio:1 TraceBatchTimeout:1s TraceSpanExporter: TraceRetryConfig: MetricReaderInterval:1s MetricRetryConfig: MetricViews:[] LogExportTimeout:1s LogBatchProcessor:true LogRetryConfig: AuthPublicKeyHex: AuthHeaders:map[]} // {InitialInterval:5s MaxInterval:30s MaxElapsedTime:1m0s} } diff --git a/pkg/beholder/httpclient.go b/pkg/beholder/httpclient.go index ee70e8243..0df44e647 100644 --- a/pkg/beholder/httpclient.go +++ b/pkg/beholder/httpclient.go @@ -14,7 +14,6 @@ import ( sdklog "go.opentelemetry.io/otel/sdk/log" sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdkresource "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -77,9 +76,13 @@ func newHTTPClient(cfg Config, otlploghttpNew otlploghttpFactory) (*Client, erro // Logger var loggerProcessor sdklog.Processor if cfg.LogBatchProcessor { + batchProcessorOpts := []sdklog.BatchProcessorOption{} + if cfg.LogExportTimeout > 0 { + batchProcessorOpts = append(batchProcessorOpts, sdklog.WithExportTimeout(cfg.LogExportTimeout)) // Default is 30s + } loggerProcessor = sdklog.NewBatchProcessor( sharedLogExporter, - sdklog.WithExportTimeout(cfg.LogExportTimeout), // Default is 30s + batchProcessorOpts..., ) } else { loggerProcessor = sdklog.NewSimpleProcessor(sharedLogExporter) @@ -117,9 +120,13 @@ func newHTTPClient(cfg Config, otlploghttpNew otlploghttpFactory) (*Client, erro // Message Emitter var messageLogProcessor sdklog.Processor if cfg.EmitterBatchProcessor { + batchProcessorOpts := []sdklog.BatchProcessorOption{} + if cfg.EmitterExportTimeout > 0 { + batchProcessorOpts = append(batchProcessorOpts, sdklog.WithExportTimeout(cfg.EmitterExportTimeout)) // Default is 30s + } messageLogProcessor = sdklog.NewBatchProcessor( sharedLogExporter, - sdklog.WithExportTimeout(cfg.EmitterExportTimeout), // Default is 30s + batchProcessorOpts..., // Default is 30s ) } else { messageLogProcessor = sdklog.NewSimpleProcessor(sharedLogExporter) @@ -181,9 +188,12 @@ func newHTTPTracerProvider(config Config, resource *sdkresource.Resource, tlsCon if err != nil { return nil, err } - + batcherOpts := []sdktrace.BatchSpanProcessorOption{} + if config.TraceBatchTimeout > 0 { + batcherOpts = append(batcherOpts, sdktrace.WithBatchTimeout(config.TraceBatchTimeout)) // Default is 5s + } opts := []sdktrace.TracerProviderOption{ - sdktrace.WithBatcher(exporter, trace.WithBatchTimeout(config.TraceBatchTimeout)), // Default is 5s + sdktrace.WithBatcher(exporter, batcherOpts...), sdktrace.WithResource(resource), sdktrace.WithSampler( sdktrace.ParentBased( @@ -231,6 +241,7 @@ func newHTTPMeterProvider(config Config, resource *sdkresource.Resource, tlsConf sdkmetric.WithInterval(config.MetricReaderInterval), // Default is 10s )), sdkmetric.WithResource(resource), + sdkmetric.WithView(config.MetricViews...), ) return mp, nil } diff --git a/pkg/capabilities/actions/readcontract/action_builders_generated.go b/pkg/capabilities/actions/readcontract/action_builders_generated.go new file mode 100644 index 000000000..dad3f4d49 --- /dev/null +++ b/pkg/capabilities/actions/readcontract/action_builders_generated.go @@ -0,0 +1,90 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package readcontract + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" +) + +func (cfg Config) New(w *sdk.WorkflowSpecFactory, ref string, input ActionInput) OutputCap { + + def := sdk.StepDefinition{ + ID: "read-contract-action@1.0.0", Ref: ref, + Inputs: input.ToSteps(), + Config: map[string]any{ + "ContractAddress": cfg.ContractAddress, + "ContractName": cfg.ContractName, + "ContractReaderConfig": cfg.ContractReaderConfig, + "ReadIdentifier": cfg.ReadIdentifier, + }, + CapabilityType: capabilities.CapabilityTypeAction, + } + + step := sdk.Step[Output]{Definition: def} + raw := step.AddTo(w) + return OutputWrapper(raw) +} + +// OutputWrapper allows access to field from an sdk.CapDefinition[Output] +func OutputWrapper(raw sdk.CapDefinition[Output]) OutputCap { + wrapped, ok := raw.(OutputCap) + if ok { + return wrapped + } + return &outputCap{CapDefinition: raw} +} + +type OutputCap interface { + sdk.CapDefinition[Output] + LatestValue() sdk.CapDefinition[any] + private() +} + +type outputCap struct { + sdk.CapDefinition[Output] +} + +func (*outputCap) private() {} +func (c *outputCap) LatestValue() sdk.CapDefinition[any] { + return sdk.AccessField[Output, any](c.CapDefinition, "LatestValue") +} + +func ConstantOutput(value Output) OutputCap { + return &outputCap{CapDefinition: sdk.ConstantDefinition(value)} +} + +func NewOutputFromFields( + latestValue sdk.CapDefinition[any]) OutputCap { + return &simpleOutput{ + CapDefinition: sdk.ComponentCapDefinition[Output]{ + "LatestValue": latestValue.Ref(), + }, + latestValue: latestValue, + } +} + +type simpleOutput struct { + sdk.CapDefinition[Output] + latestValue sdk.CapDefinition[any] +} + +func (c *simpleOutput) LatestValue() sdk.CapDefinition[any] { + return c.latestValue +} + +func (c *simpleOutput) private() {} + +type ActionInput struct { + ConfidenceLevel sdk.CapDefinition[string] + Params sdk.CapDefinition[InputParams] +} + +func (input ActionInput) ToSteps() sdk.StepInputs { + return sdk.StepInputs{ + Mapping: map[string]any{ + "ConfidenceLevel": input.ConfidenceLevel.Ref(), + "Params": input.Params.Ref(), + }, + } +} diff --git a/pkg/capabilities/actions/readcontract/readcontract_action-schema.json b/pkg/capabilities/actions/readcontract/readcontract_action-schema.json new file mode 100644 index 000000000..de94037d6 --- /dev/null +++ b/pkg/capabilities/actions/readcontract/readcontract_action-schema.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/readcontract/read-contract-action@1.0.0", + "$defs": { + "Config": { + "type": "object", + "properties": { + "ContractReaderConfig": { + "type": "string" + }, + "ReadIdentifier": { + "type": "string" + }, + "ContractAddress": { + "type": "string" + }, + "ContractName": { + "type": "string" + } + }, + "required": ["ContractReaderConfig", "ReadIdentifier", "ContractAddress", "ContractName"] + }, + "Input": { + "type": "object", + "properties": { + "ConfidenceLevel": { + "type": "string" + }, + "Params": { + "type": "object", + "additionalProperties": true + } + }, + "required": ["ConfidenceLevel", "Params"] + }, + "Output": { + "type": "object", + "properties": { + "LatestValue": { + "type": ["object", "string", "boolean", "null", "array"] + } + }, + "required": ["LatestValue"] + } + }, + "type": "object", + "properties": { + "Config": { + "$ref": "#/$defs/Config" + }, + "Inputs": { + "$ref": "#/$defs/Input" + }, + "Outputs": { + "$ref": "#/$defs/Output" + } + } +} \ No newline at end of file diff --git a/pkg/capabilities/actions/readcontract/readcontract_action_generated.go b/pkg/capabilities/actions/readcontract/readcontract_action_generated.go new file mode 100644 index 000000000..8f19f8da4 --- /dev/null +++ b/pkg/capabilities/actions/readcontract/readcontract_action_generated.go @@ -0,0 +1,115 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package readcontract + +import ( + "encoding/json" + "fmt" +) + +type Action struct { + // Config corresponds to the JSON schema field "Config". + Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" mapstructure:"Config,omitempty"` + + // Inputs corresponds to the JSON schema field "Inputs". + Inputs *Input `json:"Inputs,omitempty" yaml:"Inputs,omitempty" mapstructure:"Inputs,omitempty"` + + // Outputs corresponds to the JSON schema field "Outputs". + Outputs *Output `json:"Outputs,omitempty" yaml:"Outputs,omitempty" mapstructure:"Outputs,omitempty"` +} + +type Config struct { + // ContractAddress corresponds to the JSON schema field "ContractAddress". + ContractAddress string `json:"ContractAddress" yaml:"ContractAddress" mapstructure:"ContractAddress"` + + // ContractName corresponds to the JSON schema field "ContractName". + ContractName string `json:"ContractName" yaml:"ContractName" mapstructure:"ContractName"` + + // ContractReaderConfig corresponds to the JSON schema field + // "ContractReaderConfig". + ContractReaderConfig string `json:"ContractReaderConfig" yaml:"ContractReaderConfig" mapstructure:"ContractReaderConfig"` + + // ReadIdentifier corresponds to the JSON schema field "ReadIdentifier". + ReadIdentifier string `json:"ReadIdentifier" yaml:"ReadIdentifier" mapstructure:"ReadIdentifier"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Config) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["ContractAddress"]; raw != nil && !ok { + return fmt.Errorf("field ContractAddress in Config: required") + } + if _, ok := raw["ContractName"]; raw != nil && !ok { + return fmt.Errorf("field ContractName in Config: required") + } + if _, ok := raw["ContractReaderConfig"]; raw != nil && !ok { + return fmt.Errorf("field ContractReaderConfig in Config: required") + } + if _, ok := raw["ReadIdentifier"]; raw != nil && !ok { + return fmt.Errorf("field ReadIdentifier in Config: required") + } + type Plain Config + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Config(plain) + return nil +} + +type Input struct { + // ConfidenceLevel corresponds to the JSON schema field "ConfidenceLevel". + ConfidenceLevel string `json:"ConfidenceLevel" yaml:"ConfidenceLevel" mapstructure:"ConfidenceLevel"` + + // Params corresponds to the JSON schema field "Params". + Params InputParams `json:"Params" yaml:"Params" mapstructure:"Params"` +} + +type InputParams map[string]interface{} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Input) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["ConfidenceLevel"]; raw != nil && !ok { + return fmt.Errorf("field ConfidenceLevel in Input: required") + } + if _, ok := raw["Params"]; raw != nil && !ok { + return fmt.Errorf("field Params in Input: required") + } + type Plain Input + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Input(plain) + return nil +} + +type Output struct { + // LatestValue corresponds to the JSON schema field "LatestValue". + LatestValue interface{} `json:"LatestValue" yaml:"LatestValue" mapstructure:"LatestValue"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Output) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["LatestValue"]; raw != nil && !ok { + return fmt.Errorf("field LatestValue in Output: required") + } + type Plain Output + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Output(plain) + return nil +} diff --git a/pkg/capabilities/actions/readcontract/readcontracttest/action_mock_generated.go b/pkg/capabilities/actions/readcontract/readcontracttest/action_mock_generated.go new file mode 100644 index 000000000..ca5f1b321 --- /dev/null +++ b/pkg/capabilities/actions/readcontract/readcontracttest/action_mock_generated.go @@ -0,0 +1,27 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package readcontracttest + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/readcontract" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk/testutils" +) + +// Action registers a new capability mock with the runner +// if another mock is registered for the same capability with for a step, it will take priority for that step. +func Action(runner *testutils.Runner, fn func(input readcontract.Input) (readcontract.Output, error)) *testutils.Mock[readcontract.Input, readcontract.Output] { + mock := testutils.MockCapability[readcontract.Input, readcontract.Output]("read-contract-action@1.0.0", fn) + runner.MockCapability("read-contract-action@1.0.0", nil, mock) + return mock +} + +// ActionForStep registers a new capability mock with the runner, but only for a given step. +// if another mock was registered for the same capability without a step, this mock will take priority for that step. +func ActionForStep(runner *testutils.Runner, step string, mockFn func(input readcontract.Input) (readcontract.Output, error)) *testutils.Mock[readcontract.Input, readcontract.Output] { + fn := mockFn + mock := testutils.MockCapability[readcontract.Input, readcontract.Output]("read-contract-action@1.0.0", fn) + runner.MockCapability("read-contract-action@1.0.0", &step, mock) + return mock +} diff --git a/pkg/capabilities/cli/cmd/generator_test.go b/pkg/capabilities/cli/cmd/generator_test.go index e47bef18a..782297473 100644 --- a/pkg/capabilities/cli/cmd/generator_test.go +++ b/pkg/capabilities/cli/cmd/generator_test.go @@ -253,7 +253,7 @@ func TestTypeGeneration(t *testing.T) { }) t.Run("casing is respected from the json schema", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Owner: "owner", Name: "name"}) + workflow := sdk.NewWorkflowSpecFactory() ai := basicaction.ActionConfig{CamelCaseInSchemaForTesting: "foo", SnakeCaseInSchemaForTesting: 12}. New(workflow, "ref", basicaction.ActionInput{InputThing: sdk.ConstantDefinition[bool](true)}) spec, _ := workflow.Spec() diff --git a/pkg/capabilities/consensus/ocr3/factory.go b/pkg/capabilities/consensus/ocr3/factory.go index d634121b7..04f062eec 100644 --- a/pkg/capabilities/consensus/ocr3/factory.go +++ b/pkg/capabilities/consensus/ocr3/factory.go @@ -22,7 +22,8 @@ type factory struct { } const ( - defaultMaxPhaseOutputBytes = 100000 + // TODO(KS-617): read this from contract config + defaultMaxPhaseOutputBytes = 1000000 // 1 MB defaultMaxReportCount = 20 ) diff --git a/pkg/capabilities/consensus/ocr3/ocr3.go b/pkg/capabilities/consensus/ocr3/ocr3.go index 1e38e9af5..5209d8f63 100644 --- a/pkg/capabilities/consensus/ocr3/ocr3.go +++ b/pkg/capabilities/consensus/ocr3/ocr3.go @@ -21,7 +21,8 @@ var _ ocr3rp.ProviderServer[commontypes.PluginProvider] = (*Capability)(nil) type Capability struct { loop.Plugin reportingplugins.PluginProviderServer - config Config + config Config + capabilityRegistry core.CapabilitiesRegistry } type Config struct { @@ -101,6 +102,8 @@ func (o *Capability) NewReportingPluginFactory(ctx context.Context, cfg core.Rep return nil, err } + o.capabilityRegistry = capabilityRegistry + return factory, err } @@ -109,3 +112,17 @@ func (o *Capability) NewValidationService(ctx context.Context) (core.ValidationS o.SubService(s) return s, nil } + +func (o *Capability) Close() error { + o.Plugin.Close() + + if o.capabilityRegistry == nil { + return nil + } + + if err := o.capabilityRegistry.Remove(context.TODO(), o.config.capability.ID); err != nil { + return err + } + + return nil +} diff --git a/pkg/capabilities/consensus/ocr3/ocr3_test.go b/pkg/capabilities/consensus/ocr3/ocr3_test.go index e215c13bf..5c89f5707 100644 --- a/pkg/capabilities/consensus/ocr3/ocr3_test.go +++ b/pkg/capabilities/consensus/ocr3/ocr3_test.go @@ -55,11 +55,18 @@ func TestOCR3_ReportingFactoryIsAService(t *testing.T) { var rs core.RelayerSet r := mocks.NewCapabilitiesRegistry(t) r.On("Add", mock.Anything, o.config.capability).Return(nil) + r.On("Remove", mock.Anything, o.config.capability.ID).Return(nil) factory, err := o.NewReportingPluginFactory(ctx, core.ReportingPluginServiceConfig{}, p, pr, tc, el, r, kv, rs) require.NoError(t, err) require.NoError(t, factory.Start(ctx)) + r.AssertCalled(t, "Add", mock.Anything, o.config.capability) assert.Nil(t, factory.Ready()) + + err = o.Close() + require.NoError(t, err) + + r.AssertCalled(t, "Remove", mock.Anything, o.config.capability.ID) } diff --git a/pkg/capabilities/consensus/ocr3/ocr3cap/identical_consensus_test.go b/pkg/capabilities/consensus/ocr3/ocr3cap/identical_consensus_test.go index fdf690649..0b3d02146 100644 --- a/pkg/capabilities/consensus/ocr3/ocr3cap/identical_consensus_test.go +++ b/pkg/capabilities/consensus/ocr3/ocr3cap/identical_consensus_test.go @@ -15,10 +15,7 @@ import ( func TestIdenticalConsensus(t *testing.T) { t.Parallel() - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{ - Owner: "0x1234", - Name: "Test", - }) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1234", Number: 1}.New(workflow) @@ -43,8 +40,6 @@ func TestIdenticalConsensus(t *testing.T) { require.NoError(t, err) expected := sdk.WorkflowSpec{ - Name: "Test", - Owner: "0x1234", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", diff --git a/pkg/capabilities/consensus/ocr3/ocr3cap/reduce_consensus_test.go b/pkg/capabilities/consensus/ocr3/ocr3cap/reduce_consensus_test.go index b526f65ca..282949eb0 100644 --- a/pkg/capabilities/consensus/ocr3/ocr3cap/reduce_consensus_test.go +++ b/pkg/capabilities/consensus/ocr3/ocr3cap/reduce_consensus_test.go @@ -16,10 +16,7 @@ import ( func TestReduceConsensus(t *testing.T) { t.Parallel() - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{ - Owner: "0x1234", - Name: "Test", - }) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1234", Number: 1}.New(workflow) @@ -73,8 +70,6 @@ func TestReduceConsensus(t *testing.T) { require.NoError(t, err) expected := sdk.WorkflowSpec{ - Name: "Test", - Owner: "0x1234", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", diff --git a/pkg/capabilities/triggers/cron/cron_trigger-schema.json b/pkg/capabilities/triggers/cron/cron_trigger-schema.json new file mode 100644 index 000000000..5710378a4 --- /dev/null +++ b/pkg/capabilities/triggers/cron/cron_trigger-schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers/cron/cron-trigger@1.0.0", + "$defs": { + "Payload": { + "type": "object", + "properties": { + "ActualExecutionTime": { + "type": "string", + "description": "Time that cron trigger's task execution occurred (RFC3339Nano formatted)" + }, + "ScheduledExecutionTime": { + "type": "string", + "description": "Time that cron trigger's task execution had been scheduled to occur (RFC3339Nano formatted)" + } + }, + "required": ["ActualExecutionTime", "ScheduledExecutionTime"], + "additionalProperties": false + }, + "Config": { + "type": "object", + "properties": { + "schedule": { + "type": "string" + } + }, + "required": ["schedule"], + "additionalProperties": false + } + }, + "type": "object", + "properties": { + "config": { + "$ref": "#/$defs/Config" + }, + "outputs": { + "$ref": "#/$defs/Payload" + } + }, + "required": ["config", "outputs"], + "additionalProperties": false, + "description": "A trigger that uses a cron schedule to run periodically at fixed times, dates, or intervals." +} \ No newline at end of file diff --git a/pkg/capabilities/triggers/cron/cron_trigger_generated.go b/pkg/capabilities/triggers/cron/cron_trigger_generated.go new file mode 100644 index 000000000..5c2e2a5c0 --- /dev/null +++ b/pkg/capabilities/triggers/cron/cron_trigger_generated.go @@ -0,0 +1,92 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package cron + +import ( + "encoding/json" + "fmt" +) + +type Config struct { + // Schedule corresponds to the JSON schema field "schedule". + Schedule string `json:"schedule" yaml:"schedule" mapstructure:"schedule"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Config) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["schedule"]; raw != nil && !ok { + return fmt.Errorf("field schedule in Config: required") + } + type Plain Config + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Config(plain) + return nil +} + +type Payload struct { + // Time that cron trigger's task execution occurred (RFC3339Nano formatted) + ActualExecutionTime string `json:"ActualExecutionTime" yaml:"ActualExecutionTime" mapstructure:"ActualExecutionTime"` + + // Time that cron trigger's task execution had been scheduled to occur + // (RFC3339Nano formatted) + ScheduledExecutionTime string `json:"ScheduledExecutionTime" yaml:"ScheduledExecutionTime" mapstructure:"ScheduledExecutionTime"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Payload) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["ActualExecutionTime"]; raw != nil && !ok { + return fmt.Errorf("field ActualExecutionTime in Payload: required") + } + if _, ok := raw["ScheduledExecutionTime"]; raw != nil && !ok { + return fmt.Errorf("field ScheduledExecutionTime in Payload: required") + } + type Plain Payload + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Payload(plain) + return nil +} + +// A trigger that uses a cron schedule to run periodically at fixed times, dates, +// or intervals. +type Trigger struct { + // Config corresponds to the JSON schema field "config". + Config Config `json:"config" yaml:"config" mapstructure:"config"` + + // Outputs corresponds to the JSON schema field "outputs". + Outputs Payload `json:"outputs" yaml:"outputs" mapstructure:"outputs"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *Trigger) UnmarshalJSON(b []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(b, &raw); err != nil { + return err + } + if _, ok := raw["config"]; raw != nil && !ok { + return fmt.Errorf("field config in Trigger: required") + } + if _, ok := raw["outputs"]; raw != nil && !ok { + return fmt.Errorf("field outputs in Trigger: required") + } + type Plain Trigger + var plain Plain + if err := json.Unmarshal(b, &plain); err != nil { + return err + } + *j = Trigger(plain) + return nil +} diff --git a/pkg/capabilities/triggers/cron/crontest/trigger_mock_generated.go b/pkg/capabilities/triggers/cron/crontest/trigger_mock_generated.go new file mode 100644 index 000000000..ad683b1d5 --- /dev/null +++ b/pkg/capabilities/triggers/cron/crontest/trigger_mock_generated.go @@ -0,0 +1,17 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package crontest + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers/cron" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk/testutils" +) + +// Trigger registers a new capability mock with the runner +func Trigger(runner *testutils.Runner, fn func() (cron.Payload, error)) *testutils.TriggerMock[cron.Payload] { + mock := testutils.MockTrigger[cron.Payload]("cron-trigger@1.0.0", fn) + runner.MockCapability("cron-trigger@1.0.0", nil, mock) + return mock +} diff --git a/pkg/capabilities/triggers/cron/trigger_builders_generated.go b/pkg/capabilities/triggers/cron/trigger_builders_generated.go new file mode 100644 index 000000000..e84dac176 --- /dev/null +++ b/pkg/capabilities/triggers/cron/trigger_builders_generated.go @@ -0,0 +1,84 @@ +// Code generated by github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli, DO NOT EDIT. + +package cron + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" +) + +func (cfg Config) New(w *sdk.WorkflowSpecFactory) PayloadCap { + ref := "trigger" + def := sdk.StepDefinition{ + ID: "cron-trigger@1.0.0", Ref: ref, + Inputs: sdk.StepInputs{}, + Config: map[string]any{ + "schedule": cfg.Schedule, + }, + CapabilityType: capabilities.CapabilityTypeTrigger, + } + + step := sdk.Step[Payload]{Definition: def} + raw := step.AddTo(w) + return PayloadWrapper(raw) +} + +// PayloadWrapper allows access to field from an sdk.CapDefinition[Payload] +func PayloadWrapper(raw sdk.CapDefinition[Payload]) PayloadCap { + wrapped, ok := raw.(PayloadCap) + if ok { + return wrapped + } + return &payloadCap{CapDefinition: raw} +} + +type PayloadCap interface { + sdk.CapDefinition[Payload] + ActualExecutionTime() sdk.CapDefinition[string] + ScheduledExecutionTime() sdk.CapDefinition[string] + private() +} + +type payloadCap struct { + sdk.CapDefinition[Payload] +} + +func (*payloadCap) private() {} +func (c *payloadCap) ActualExecutionTime() sdk.CapDefinition[string] { + return sdk.AccessField[Payload, string](c.CapDefinition, "ActualExecutionTime") +} +func (c *payloadCap) ScheduledExecutionTime() sdk.CapDefinition[string] { + return sdk.AccessField[Payload, string](c.CapDefinition, "ScheduledExecutionTime") +} + +func ConstantPayload(value Payload) PayloadCap { + return &payloadCap{CapDefinition: sdk.ConstantDefinition(value)} +} + +func NewPayloadFromFields( + actualExecutionTime sdk.CapDefinition[string], + scheduledExecutionTime sdk.CapDefinition[string]) PayloadCap { + return &simplePayload{ + CapDefinition: sdk.ComponentCapDefinition[Payload]{ + "ActualExecutionTime": actualExecutionTime.Ref(), + "ScheduledExecutionTime": scheduledExecutionTime.Ref(), + }, + actualExecutionTime: actualExecutionTime, + scheduledExecutionTime: scheduledExecutionTime, + } +} + +type simplePayload struct { + sdk.CapDefinition[Payload] + actualExecutionTime sdk.CapDefinition[string] + scheduledExecutionTime sdk.CapDefinition[string] +} + +func (c *simplePayload) ActualExecutionTime() sdk.CapDefinition[string] { + return c.actualExecutionTime +} +func (c *simplePayload) ScheduledExecutionTime() sdk.CapDefinition[string] { + return c.scheduledExecutionTime +} + +func (c *simplePayload) private() {} diff --git a/pkg/loop/config.go b/pkg/loop/config.go index 6e18e60ae..e63f72f2f 100644 --- a/pkg/loop/config.go +++ b/pkg/loop/config.go @@ -142,6 +142,14 @@ func (e *EnvConfig) parse() error { e.TelemetryTraceSampleRatio = getFloat64OrZero(envTelemetryTraceSampleRatio) e.TelemetryAuthHeaders = getMap(envTelemetryAuthHeader) e.TelemetryAuthPubKeyHex = os.Getenv(envTelemetryAuthPubKeyHex) + e.TelemetryEmitterBatchProcessor, err = getBool(envTelemetryEmitterBatchProcessor) + if err != nil { + return fmt.Errorf("failed to parse %s: %w", envTelemetryEmitterBatchProcessor, err) + } + e.TelemetryEmitterExportTimeout, err = time.ParseDuration(os.Getenv(envTelemetryEmitterExportTimeout)) + if err != nil { + return fmt.Errorf("failed to parse %s: %w", envTelemetryEmitterExportTimeout, err) + } } return nil } diff --git a/pkg/loop/config_test.go b/pkg/loop/config_test.go index b2eb18745..78d177aa4 100644 --- a/pkg/loop/config_test.go +++ b/pkg/loop/config_test.go @@ -1,6 +1,7 @@ package loop import ( + "maps" "net/url" "os" "strconv" @@ -18,34 +19,65 @@ import ( func TestEnvConfig_parse(t *testing.T) { cases := []struct { - name string - envVars map[string]string - expectError bool - expectedDatabaseURL string - expectedPrometheusPort int - expectedTracingEnabled bool - expectedTracingCollectorTarget string - expectedTracingSamplingRatio float64 - expectedTracingTLSCertPath string + name string + envVars map[string]string + expectError bool + expectedDatabaseURL string + expectedPrometheusPort int + expectedTracingEnabled bool + expectedTracingCollectorTarget string + expectedTracingSamplingRatio float64 + expectedTracingTLSCertPath string + expectedTelemetryEnabled bool + expectedTelemetryEndpoint string + expectedTelemetryInsecureConn bool + expectedTelemetryCACertFile string + expectedTelemetryAttributes OtelAttributes + expectedTelemetryTraceSampleRatio float64 + expectedTelemetryAuthHeaders map[string]string + expectedTelemetryAuthPubKeyHex string + expectedTelemetryEmitterBatchProcessor bool + expectedTelemetryEmitterExportTimeout time.Duration }{ { name: "All variables set correctly", envVars: map[string]string{ - envDatabaseURL: "postgres://user:password@localhost:5432/db", - envPromPort: "8080", - envTracingEnabled: "true", - envTracingCollectorTarget: "some:target", - envTracingSamplingRatio: "1.0", - envTracingTLSCertPath: "internal/test/fixtures/client.pem", - envTracingAttribute + "XYZ": "value", + envDatabaseURL: "postgres://user:password@localhost:5432/db", + envPromPort: "8080", + envTracingEnabled: "true", + envTracingCollectorTarget: "some:target", + envTracingSamplingRatio: "1.0", + envTracingTLSCertPath: "internal/test/fixtures/client.pem", + envTracingAttribute + "XYZ": "value", + envTelemetryEnabled: "true", + envTelemetryEndpoint: "example.com/beholder", + envTelemetryInsecureConn: "true", + envTelemetryCACertFile: "foo/bar", + envTelemetryAttribute + "foo": "bar", + envTelemetryAttribute + "baz": "42", + envTelemetryTraceSampleRatio: "0.42", + envTelemetryAuthHeader + "header-key": "header-value", + envTelemetryAuthPubKeyHex: "pub-key-hex", + envTelemetryEmitterBatchProcessor: "true", + envTelemetryEmitterExportTimeout: "1s", }, - expectError: false, - expectedDatabaseURL: "postgres://user:password@localhost:5432/db", - expectedPrometheusPort: 8080, - expectedTracingEnabled: true, - expectedTracingCollectorTarget: "some:target", - expectedTracingSamplingRatio: 1.0, - expectedTracingTLSCertPath: "internal/test/fixtures/client.pem", + expectError: false, + expectedDatabaseURL: "postgres://user:password@localhost:5432/db", + expectedPrometheusPort: 8080, + expectedTracingEnabled: true, + expectedTracingCollectorTarget: "some:target", + expectedTracingSamplingRatio: 1.0, + expectedTracingTLSCertPath: "internal/test/fixtures/client.pem", + expectedTelemetryEnabled: true, + expectedTelemetryEndpoint: "example.com/beholder", + expectedTelemetryInsecureConn: true, + expectedTelemetryCACertFile: "foo/bar", + expectedTelemetryAttributes: OtelAttributes{"foo": "bar", "baz": "42"}, + expectedTelemetryTraceSampleRatio: 0.42, + expectedTelemetryAuthHeaders: map[string]string{"header-key": "header-value"}, + expectedTelemetryAuthPubKeyHex: "pub-key-hex", + expectedTelemetryEmitterBatchProcessor: true, + expectedTelemetryEmitterExportTimeout: 1 * time.Second, }, { name: "CL_DATABASE_URL parse error", @@ -106,6 +138,36 @@ func TestEnvConfig_parse(t *testing.T) { if config.TracingTLSCertPath != tc.expectedTracingTLSCertPath { t.Errorf("Expected tracingTLSCertPath %s, got %s", tc.expectedTracingTLSCertPath, config.TracingTLSCertPath) } + if config.TelemetryEnabled != tc.expectedTelemetryEnabled { + t.Errorf("Expected telemetryEnabled %v, got %v", tc.expectedTelemetryEnabled, config.TelemetryEnabled) + } + if config.TelemetryEndpoint != tc.expectedTelemetryEndpoint { + t.Errorf("Expected telemetryEndpoint %s, got %s", tc.expectedTelemetryEndpoint, config.TelemetryEndpoint) + } + if config.TelemetryInsecureConnection != tc.expectedTelemetryInsecureConn { + t.Errorf("Expected telemetryInsecureConn %v, got %v", tc.expectedTelemetryInsecureConn, config.TelemetryInsecureConnection) + } + if config.TelemetryCACertFile != tc.expectedTelemetryCACertFile { + t.Errorf("Expected telemetryCACertFile %s, got %s", tc.expectedTelemetryCACertFile, config.TelemetryCACertFile) + } + if !maps.Equal(config.TelemetryAttributes, tc.expectedTelemetryAttributes) { + t.Errorf("Expected telemetryAttributes %v, got %v", tc.expectedTelemetryAttributes, config.TelemetryAttributes) + } + if config.TelemetryTraceSampleRatio != tc.expectedTelemetryTraceSampleRatio { + t.Errorf("Expected telemetryTraceSampleRatio %f, got %f", tc.expectedTelemetryTraceSampleRatio, config.TelemetryTraceSampleRatio) + } + if !maps.Equal(config.TelemetryAuthHeaders, tc.expectedTelemetryAuthHeaders) { + t.Errorf("Expected telemetryAuthHeaders %v, got %v", tc.expectedTelemetryAuthHeaders, config.TelemetryAuthHeaders) + } + if config.TelemetryAuthPubKeyHex != tc.expectedTelemetryAuthPubKeyHex { + t.Errorf("Expected telemetryAuthPubKeyHex %s, got %s", tc.expectedTelemetryAuthPubKeyHex, config.TelemetryAuthPubKeyHex) + } + if config.TelemetryEmitterBatchProcessor != tc.expectedTelemetryEmitterBatchProcessor { + t.Errorf("Expected telemetryEmitterBatchProcessor %v, got %v", tc.expectedTelemetryEmitterBatchProcessor, config.TelemetryEmitterBatchProcessor) + } + if config.TelemetryEmitterExportTimeout != tc.expectedTelemetryEmitterExportTimeout { + t.Errorf("Expected telemetryEmitterExportTimeout %v, got %v", tc.expectedTelemetryEmitterExportTimeout, config.TelemetryEmitterExportTimeout) + } } } }) diff --git a/pkg/loop/internal/core/services/capability/capabilities_registry.go b/pkg/loop/internal/core/services/capability/capabilities_registry.go index 8f5564b35..a8281b999 100644 --- a/pkg/loop/internal/core/services/capability/capabilities_registry.go +++ b/pkg/loop/internal/core/services/capability/capabilities_registry.go @@ -264,6 +264,19 @@ func (cr *capabilitiesRegistryClient) Add(ctx context.Context, c capabilities.Ba return nil } +func (cr *capabilitiesRegistryClient) Remove(ctx context.Context, ID string) error { + req := &pb.RemoveRequest{ + Id: ID, + } + + _, err := cr.grpc.Remove(ctx, req) + if err != nil { + return err + } + + return nil +} + func NewCapabilitiesRegistryClient(cc grpc.ClientConnInterface, b *net.BrokerExt) *capabilitiesRegistryClient { return &capabilitiesRegistryClient{grpc: pb.NewCapabilitiesRegistryClient(cc), BrokerExt: b.WithName("CapabilitiesRegistryClient")} } @@ -526,6 +539,14 @@ func (c *capabilitiesRegistryServer) Add(ctx context.Context, request *pb.AddReq return &emptypb.Empty{}, nil } +func (c *capabilitiesRegistryServer) Remove(ctx context.Context, request *pb.RemoveRequest) (*emptypb.Empty, error) { + err := c.impl.Remove(ctx, request.Id) + if err != nil { + return &emptypb.Empty{}, err + } + return &emptypb.Empty{}, nil +} + func NewCapabilitiesRegistryServer(b *net.BrokerExt, i core.CapabilitiesRegistry) *capabilitiesRegistryServer { return &capabilitiesRegistryServer{ BrokerExt: b.WithName("CapabilitiesRegistryServer"), diff --git a/pkg/loop/internal/net/client.go b/pkg/loop/internal/net/client.go index 0c96eafd4..fbe5978f6 100644 --- a/pkg/loop/internal/net/client.go +++ b/pkg/loop/internal/net/client.go @@ -10,6 +10,7 @@ import ( "google.golang.org/grpc" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb" ) var _ grpc.ClientConnInterface = (*AtomicClient)(nil) @@ -58,7 +59,12 @@ func (c *clientConn) Invoke(ctx context.Context, method string, args interface{} for cc != nil { err := cc.Invoke(ctx, method, args, reply, opts...) if isErrTerminal(err) { - c.Logger.Warnw("clientConn: Invoke: terminal error, refreshing connection", "err", err) + if method == pb.Service_Close_FullMethodName { + // don't reconnect just to call Close + c.Logger.Warnw("clientConn: Invoke: terminal error", "method", method, "err", err) + return err + } + c.Logger.Warnw("clientConn: Invoke: terminal error, refreshing connection", "method", method, "err", err) cc = c.refresh(ctx, cc) continue } diff --git a/pkg/loop/internal/pb/capabilities_registry.pb.go b/pkg/loop/internal/pb/capabilities_registry.pb.go index ea7afed71..513b9c993 100644 --- a/pkg/loop/internal/pb/capabilities_registry.pb.go +++ b/pkg/loop/internal/pb/capabilities_registry.pb.go @@ -799,6 +799,54 @@ func (x *AddRequest) GetType() ExecuteAPIType { return ExecuteAPIType_EXECUTE_API_TYPE_UNKNOWN } +// Remove has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.CapabilitiesRegistry.Remove]. +type RemoveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *RemoveRequest) Reset() { + *x = RemoveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveRequest) ProtoMessage() {} + +func (x *RemoveRequest) ProtoReflect() protoreflect.Message { + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveRequest.ProtoReflect.Descriptor instead. +func (*RemoveRequest) Descriptor() ([]byte, []int) { + return file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP(), []int{14} +} + +func (x *RemoveRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + type ConfigForCapabilityRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -811,7 +859,7 @@ type ConfigForCapabilityRequest struct { func (x *ConfigForCapabilityRequest) Reset() { *x = ConfigForCapabilityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[14] + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -824,7 +872,7 @@ func (x *ConfigForCapabilityRequest) String() string { func (*ConfigForCapabilityRequest) ProtoMessage() {} func (x *ConfigForCapabilityRequest) ProtoReflect() protoreflect.Message { - mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[14] + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -837,7 +885,7 @@ func (x *ConfigForCapabilityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigForCapabilityRequest.ProtoReflect.Descriptor instead. func (*ConfigForCapabilityRequest) Descriptor() ([]byte, []int) { - return file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP(), []int{14} + return file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP(), []int{15} } func (x *ConfigForCapabilityRequest) GetCapabilityID() string { @@ -865,7 +913,7 @@ type ConfigForCapabilityReply struct { func (x *ConfigForCapabilityReply) Reset() { *x = ConfigForCapabilityReply{} if protoimpl.UnsafeEnabled { - mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[15] + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -878,7 +926,7 @@ func (x *ConfigForCapabilityReply) String() string { func (*ConfigForCapabilityReply) ProtoMessage() {} func (x *ConfigForCapabilityReply) ProtoReflect() protoreflect.Message { - mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[15] + mi := &file_loop_internal_pb_capabilities_registry_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -891,7 +939,7 @@ func (x *ConfigForCapabilityReply) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigForCapabilityReply.ProtoReflect.Descriptor instead. func (*ConfigForCapabilityReply) Descriptor() ([]byte, []int) { - return file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP(), []int{15} + return file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP(), []int{16} } func (x *ConfigForCapabilityReply) GetCapabilityConfig() *pb.CapabilityConfig { @@ -965,66 +1013,72 @@ var file_loop_internal_pb_capabilities_registry_proto_rawDesc = []byte{ 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x50, 0x49, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x56, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x6f, 0x6e, 0x49, - 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x64, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x5f, - 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x43, 0x0a, 0x11, 0x63, 0x61, - 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x61, 0x70, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x63, - 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2a, - 0x6a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x50, 0x49, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x49, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1c, 0x0a, - 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x10, 0x02, 0x32, 0xbf, 0x04, 0x0a, 0x14, - 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x12, 0x3b, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x00, 0x12, 0x59, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, - 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x29, 0x0a, 0x03, - 0x47, 0x65, 0x74, 0x12, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x54, 0x72, - 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, - 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x65, - 0x6e, 0x73, 0x75, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, - 0x73, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x47, 0x65, - 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, - 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x03, 0x41, 0x64, - 0x64, 0x12, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, - 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, - 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x56, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x6f, 0x6e, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x64, 0x6f, 0x6e, 0x49, 0x44, 0x22, + 0x5f, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x43, 0x0a, 0x11, 0x63, + 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x61, + 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, + 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2a, 0x6a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x41, 0x50, 0x49, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, + 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1c, + 0x0a, 0x18, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x10, 0x02, 0x32, 0xf8, 0x04, 0x0a, + 0x14, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x3b, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x59, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, + 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6f, 0x72, 0x43, 0x61, 0x70, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x29, 0x0a, + 0x03, 0x47, 0x65, 0x74, 0x12, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x54, + 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, + 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, + 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x73, + 0x65, 0x6e, 0x73, 0x75, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x65, + 0x6e, 0x73, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x03, 0x41, + 0x64, 0x64, 0x12, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x37, + 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1040,7 +1094,7 @@ func file_loop_internal_pb_capabilities_registry_proto_rawDescGZIP() []byte { } var file_loop_internal_pb_capabilities_registry_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_loop_internal_pb_capabilities_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_loop_internal_pb_capabilities_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_loop_internal_pb_capabilities_registry_proto_goTypes = []interface{}{ (ExecuteAPIType)(0), // 0: loop.ExecuteAPIType (*DON)(nil), // 1: loop.DON @@ -1057,37 +1111,40 @@ var file_loop_internal_pb_capabilities_registry_proto_goTypes = []interface{}{ (*ListReply)(nil), // 12: loop.ListReply (*GetTargetReply)(nil), // 13: loop.GetTargetReply (*AddRequest)(nil), // 14: loop.AddRequest - (*ConfigForCapabilityRequest)(nil), // 15: loop.ConfigForCapabilityRequest - (*ConfigForCapabilityReply)(nil), // 16: loop.ConfigForCapabilityReply - (*pb.CapabilityConfig)(nil), // 17: loop.CapabilityConfig - (*emptypb.Empty)(nil), // 18: google.protobuf.Empty + (*RemoveRequest)(nil), // 15: loop.RemoveRequest + (*ConfigForCapabilityRequest)(nil), // 16: loop.ConfigForCapabilityRequest + (*ConfigForCapabilityReply)(nil), // 17: loop.ConfigForCapabilityReply + (*pb.CapabilityConfig)(nil), // 18: loop.CapabilityConfig + (*emptypb.Empty)(nil), // 19: google.protobuf.Empty } var file_loop_internal_pb_capabilities_registry_proto_depIdxs = []int32{ 1, // 0: loop.LocalNodeReply.workflowDON:type_name -> loop.DON 1, // 1: loop.LocalNodeReply.CapabilityDONs:type_name -> loop.DON 0, // 2: loop.GetReply.type:type_name -> loop.ExecuteAPIType 0, // 3: loop.AddRequest.type:type_name -> loop.ExecuteAPIType - 17, // 4: loop.ConfigForCapabilityReply.capability_config:type_name -> loop.CapabilityConfig - 18, // 5: loop.CapabilitiesRegistry.LocalNode:input_type -> google.protobuf.Empty - 15, // 6: loop.CapabilitiesRegistry.ConfigForCapability:input_type -> loop.ConfigForCapabilityRequest + 18, // 4: loop.ConfigForCapabilityReply.capability_config:type_name -> loop.CapabilityConfig + 19, // 5: loop.CapabilitiesRegistry.LocalNode:input_type -> google.protobuf.Empty + 16, // 6: loop.CapabilitiesRegistry.ConfigForCapability:input_type -> loop.ConfigForCapabilityRequest 3, // 7: loop.CapabilitiesRegistry.Get:input_type -> loop.GetRequest 5, // 8: loop.CapabilitiesRegistry.GetTrigger:input_type -> loop.GetTriggerRequest 7, // 9: loop.CapabilitiesRegistry.GetAction:input_type -> loop.GetActionRequest 9, // 10: loop.CapabilitiesRegistry.GetConsensus:input_type -> loop.GetConsensusRequest 11, // 11: loop.CapabilitiesRegistry.GetTarget:input_type -> loop.GetTargetRequest - 18, // 12: loop.CapabilitiesRegistry.List:input_type -> google.protobuf.Empty + 19, // 12: loop.CapabilitiesRegistry.List:input_type -> google.protobuf.Empty 14, // 13: loop.CapabilitiesRegistry.Add:input_type -> loop.AddRequest - 2, // 14: loop.CapabilitiesRegistry.LocalNode:output_type -> loop.LocalNodeReply - 16, // 15: loop.CapabilitiesRegistry.ConfigForCapability:output_type -> loop.ConfigForCapabilityReply - 4, // 16: loop.CapabilitiesRegistry.Get:output_type -> loop.GetReply - 6, // 17: loop.CapabilitiesRegistry.GetTrigger:output_type -> loop.GetTriggerReply - 8, // 18: loop.CapabilitiesRegistry.GetAction:output_type -> loop.GetActionReply - 10, // 19: loop.CapabilitiesRegistry.GetConsensus:output_type -> loop.GetConsensusReply - 13, // 20: loop.CapabilitiesRegistry.GetTarget:output_type -> loop.GetTargetReply - 12, // 21: loop.CapabilitiesRegistry.List:output_type -> loop.ListReply - 18, // 22: loop.CapabilitiesRegistry.Add:output_type -> google.protobuf.Empty - 14, // [14:23] is the sub-list for method output_type - 5, // [5:14] is the sub-list for method input_type + 15, // 14: loop.CapabilitiesRegistry.Remove:input_type -> loop.RemoveRequest + 2, // 15: loop.CapabilitiesRegistry.LocalNode:output_type -> loop.LocalNodeReply + 17, // 16: loop.CapabilitiesRegistry.ConfigForCapability:output_type -> loop.ConfigForCapabilityReply + 4, // 17: loop.CapabilitiesRegistry.Get:output_type -> loop.GetReply + 6, // 18: loop.CapabilitiesRegistry.GetTrigger:output_type -> loop.GetTriggerReply + 8, // 19: loop.CapabilitiesRegistry.GetAction:output_type -> loop.GetActionReply + 10, // 20: loop.CapabilitiesRegistry.GetConsensus:output_type -> loop.GetConsensusReply + 13, // 21: loop.CapabilitiesRegistry.GetTarget:output_type -> loop.GetTargetReply + 12, // 22: loop.CapabilitiesRegistry.List:output_type -> loop.ListReply + 19, // 23: loop.CapabilitiesRegistry.Add:output_type -> google.protobuf.Empty + 19, // 24: loop.CapabilitiesRegistry.Remove:output_type -> google.protobuf.Empty + 15, // [15:25] is the sub-list for method output_type + 5, // [5:15] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name @@ -1268,7 +1325,7 @@ func file_loop_internal_pb_capabilities_registry_proto_init() { } } file_loop_internal_pb_capabilities_registry_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConfigForCapabilityRequest); i { + switch v := v.(*RemoveRequest); i { case 0: return &v.state case 1: @@ -1280,6 +1337,18 @@ func file_loop_internal_pb_capabilities_registry_proto_init() { } } file_loop_internal_pb_capabilities_registry_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConfigForCapabilityRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_loop_internal_pb_capabilities_registry_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ConfigForCapabilityReply); i { case 0: return &v.state @@ -1298,7 +1367,7 @@ func file_loop_internal_pb_capabilities_registry_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_loop_internal_pb_capabilities_registry_proto_rawDesc, NumEnums: 1, - NumMessages: 16, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/loop/internal/pb/capabilities_registry.proto b/pkg/loop/internal/pb/capabilities_registry.proto index a5ca7283d..12e2d908d 100644 --- a/pkg/loop/internal/pb/capabilities_registry.proto +++ b/pkg/loop/internal/pb/capabilities_registry.proto @@ -17,6 +17,7 @@ service CapabilitiesRegistry { rpc GetTarget (GetTargetRequest) returns (GetTargetReply) {} rpc List (google.protobuf.Empty) returns (ListReply) {} rpc Add (AddRequest) returns (google.protobuf.Empty) {} + rpc Remove (RemoveRequest) returns (google.protobuf.Empty) {} } enum ExecuteAPIType { @@ -104,6 +105,11 @@ message AddRequest { ExecuteAPIType type = 2; } +// Remove has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.CapabilitiesRegistry.Remove]. +message RemoveRequest { + string id = 1; +} + message ConfigForCapabilityRequest { string capabilityID = 1; uint32 donID = 2; diff --git a/pkg/loop/internal/pb/capabilities_registry_grpc.pb.go b/pkg/loop/internal/pb/capabilities_registry_grpc.pb.go index e7f1735be..6bba79252 100644 --- a/pkg/loop/internal/pb/capabilities_registry_grpc.pb.go +++ b/pkg/loop/internal/pb/capabilities_registry_grpc.pb.go @@ -29,6 +29,7 @@ const ( CapabilitiesRegistry_GetTarget_FullMethodName = "/loop.CapabilitiesRegistry/GetTarget" CapabilitiesRegistry_List_FullMethodName = "/loop.CapabilitiesRegistry/List" CapabilitiesRegistry_Add_FullMethodName = "/loop.CapabilitiesRegistry/Add" + CapabilitiesRegistry_Remove_FullMethodName = "/loop.CapabilitiesRegistry/Remove" ) // CapabilitiesRegistryClient is the client API for CapabilitiesRegistry service. @@ -44,6 +45,7 @@ type CapabilitiesRegistryClient interface { GetTarget(ctx context.Context, in *GetTargetRequest, opts ...grpc.CallOption) (*GetTargetReply, error) List(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListReply, error) Add(ctx context.Context, in *AddRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) } type capabilitiesRegistryClient struct { @@ -135,6 +137,15 @@ func (c *capabilitiesRegistryClient) Add(ctx context.Context, in *AddRequest, op return out, nil } +func (c *capabilitiesRegistryClient) Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, CapabilitiesRegistry_Remove_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // CapabilitiesRegistryServer is the server API for CapabilitiesRegistry service. // All implementations must embed UnimplementedCapabilitiesRegistryServer // for forward compatibility @@ -148,6 +159,7 @@ type CapabilitiesRegistryServer interface { GetTarget(context.Context, *GetTargetRequest) (*GetTargetReply, error) List(context.Context, *emptypb.Empty) (*ListReply, error) Add(context.Context, *AddRequest) (*emptypb.Empty, error) + Remove(context.Context, *RemoveRequest) (*emptypb.Empty, error) mustEmbedUnimplementedCapabilitiesRegistryServer() } @@ -182,6 +194,9 @@ func (UnimplementedCapabilitiesRegistryServer) List(context.Context, *emptypb.Em func (UnimplementedCapabilitiesRegistryServer) Add(context.Context, *AddRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Add not implemented") } +func (UnimplementedCapabilitiesRegistryServer) Remove(context.Context, *RemoveRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Remove not implemented") +} func (UnimplementedCapabilitiesRegistryServer) mustEmbedUnimplementedCapabilitiesRegistryServer() {} // UnsafeCapabilitiesRegistryServer may be embedded to opt out of forward compatibility for this service. @@ -357,6 +372,24 @@ func _CapabilitiesRegistry_Add_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _CapabilitiesRegistry_Remove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CapabilitiesRegistryServer).Remove(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CapabilitiesRegistry_Remove_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CapabilitiesRegistryServer).Remove(ctx, req.(*RemoveRequest)) + } + return interceptor(ctx, in, info, handler) +} + // CapabilitiesRegistry_ServiceDesc is the grpc.ServiceDesc for CapabilitiesRegistry service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -400,6 +433,10 @@ var CapabilitiesRegistry_ServiceDesc = grpc.ServiceDesc{ MethodName: "Add", Handler: _CapabilitiesRegistry_Add_Handler, }, + { + MethodName: "Remove", + Handler: _CapabilitiesRegistry_Remove_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "loop/internal/pb/capabilities_registry.proto", diff --git a/pkg/loop/internal/pb/chain_writer_grpc.pb.go b/pkg/loop/internal/pb/chain_writer_grpc.pb.go deleted file mode 100644 index d49a4cdf4..000000000 --- a/pkg/loop/internal/pb/chain_writer_grpc.pb.go +++ /dev/null @@ -1,184 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 -// source: chain_writer.proto - -package pb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - emptypb "google.golang.org/protobuf/types/known/emptypb" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -const ( - ChainWriter_SubmitTransaction_FullMethodName = "/loop.ChainWriter/SubmitTransaction" - ChainWriter_GetTransactionStatus_FullMethodName = "/loop.ChainWriter/GetTransactionStatus" - ChainWriter_GetFeeComponents_FullMethodName = "/loop.ChainWriter/GetFeeComponents" -) - -// ChainWriterClient is the client API for ChainWriter service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type ChainWriterClient interface { - SubmitTransaction(ctx context.Context, in *SubmitTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) - GetTransactionStatus(ctx context.Context, in *GetTransactionStatusRequest, opts ...grpc.CallOption) (*GetTransactionStatusReply, error) - GetFeeComponents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetFeeComponentsReply, error) -} - -type chainWriterClient struct { - cc grpc.ClientConnInterface -} - -func NewChainWriterClient(cc grpc.ClientConnInterface) ChainWriterClient { - return &chainWriterClient{cc} -} - -func (c *chainWriterClient) SubmitTransaction(ctx context.Context, in *SubmitTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { - out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, ChainWriter_SubmitTransaction_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *chainWriterClient) GetTransactionStatus(ctx context.Context, in *GetTransactionStatusRequest, opts ...grpc.CallOption) (*GetTransactionStatusReply, error) { - out := new(GetTransactionStatusReply) - err := c.cc.Invoke(ctx, ChainWriter_GetTransactionStatus_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *chainWriterClient) GetFeeComponents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetFeeComponentsReply, error) { - out := new(GetFeeComponentsReply) - err := c.cc.Invoke(ctx, ChainWriter_GetFeeComponents_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ChainWriterServer is the server API for ChainWriter service. -// All implementations must embed UnimplementedChainWriterServer -// for forward compatibility -type ChainWriterServer interface { - SubmitTransaction(context.Context, *SubmitTransactionRequest) (*emptypb.Empty, error) - GetTransactionStatus(context.Context, *GetTransactionStatusRequest) (*GetTransactionStatusReply, error) - GetFeeComponents(context.Context, *emptypb.Empty) (*GetFeeComponentsReply, error) - mustEmbedUnimplementedChainWriterServer() -} - -// UnimplementedChainWriterServer must be embedded to have forward compatible implementations. -type UnimplementedChainWriterServer struct { -} - -func (UnimplementedChainWriterServer) SubmitTransaction(context.Context, *SubmitTransactionRequest) (*emptypb.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method SubmitTransaction not implemented") -} -func (UnimplementedChainWriterServer) GetTransactionStatus(context.Context, *GetTransactionStatusRequest) (*GetTransactionStatusReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetTransactionStatus not implemented") -} -func (UnimplementedChainWriterServer) GetFeeComponents(context.Context, *emptypb.Empty) (*GetFeeComponentsReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetFeeComponents not implemented") -} -func (UnimplementedChainWriterServer) mustEmbedUnimplementedChainWriterServer() {} - -// UnsafeChainWriterServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ChainWriterServer will -// result in compilation errors. -type UnsafeChainWriterServer interface { - mustEmbedUnimplementedChainWriterServer() -} - -func RegisterChainWriterServer(s grpc.ServiceRegistrar, srv ChainWriterServer) { - s.RegisterService(&ChainWriter_ServiceDesc, srv) -} - -func _ChainWriter_SubmitTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SubmitTransactionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ChainWriterServer).SubmitTransaction(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ChainWriter_SubmitTransaction_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChainWriterServer).SubmitTransaction(ctx, req.(*SubmitTransactionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ChainWriter_GetTransactionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetTransactionStatusRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ChainWriterServer).GetTransactionStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ChainWriter_GetTransactionStatus_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChainWriterServer).GetTransactionStatus(ctx, req.(*GetTransactionStatusRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ChainWriter_GetFeeComponents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ChainWriterServer).GetFeeComponents(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: ChainWriter_GetFeeComponents_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ChainWriterServer).GetFeeComponents(ctx, req.(*emptypb.Empty)) - } - return interceptor(ctx, in, info, handler) -} - -// ChainWriter_ServiceDesc is the grpc.ServiceDesc for ChainWriter service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var ChainWriter_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "loop.ChainWriter", - HandlerType: (*ChainWriterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "SubmitTransaction", - Handler: _ChainWriter_SubmitTransaction_Handler, - }, - { - MethodName: "GetTransactionStatus", - Handler: _ChainWriter_GetTransactionStatus_Handler, - }, - { - MethodName: "GetFeeComponents", - Handler: _ChainWriter_GetFeeComponents_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "chain_writer.proto", -} diff --git a/pkg/loop/internal/pb/contract_reader.pb.go b/pkg/loop/internal/pb/contract_reader.pb.go index 6d781f8ec..c3b30fe47 100644 --- a/pkg/loop/internal/pb/contract_reader.pb.go +++ b/pkg/loop/internal/pb/contract_reader.pb.go @@ -505,6 +505,125 @@ func (x *QueryKeyRequest) GetAsValueType() bool { return false } +// QueryKeysRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.QueryKeys]. +type QueryKeysRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Filters []*ContractKeyFilter `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + LimitAndSort *LimitAndSort `protobuf:"bytes,2,opt,name=limit_and_sort,json=limitAndSort,proto3" json:"limit_and_sort,omitempty"` +} + +func (x *QueryKeysRequest) Reset() { + *x = QueryKeysRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_contract_reader_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryKeysRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryKeysRequest) ProtoMessage() {} + +func (x *QueryKeysRequest) ProtoReflect() protoreflect.Message { + mi := &file_contract_reader_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryKeysRequest.ProtoReflect.Descriptor instead. +func (*QueryKeysRequest) Descriptor() ([]byte, []int) { + return file_contract_reader_proto_rawDescGZIP(), []int{3} +} + +func (x *QueryKeysRequest) GetFilters() []*ContractKeyFilter { + if x != nil { + return x.Filters + } + return nil +} + +func (x *QueryKeysRequest) GetLimitAndSort() *LimitAndSort { + if x != nil { + return x.LimitAndSort + } + return nil +} + +type ContractKeyFilter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Contract *BoundContract `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + Filter *QueryKeyFilter `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"` + AsValueType bool `protobuf:"varint,4,opt,name=as_value_type,json=asValueType,proto3" json:"as_value_type,omitempty"` +} + +func (x *ContractKeyFilter) Reset() { + *x = ContractKeyFilter{} + if protoimpl.UnsafeEnabled { + mi := &file_contract_reader_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContractKeyFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractKeyFilter) ProtoMessage() {} + +func (x *ContractKeyFilter) ProtoReflect() protoreflect.Message { + mi := &file_contract_reader_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractKeyFilter.ProtoReflect.Descriptor instead. +func (*ContractKeyFilter) Descriptor() ([]byte, []int) { + return file_contract_reader_proto_rawDescGZIP(), []int{4} +} + +func (x *ContractKeyFilter) GetContract() *BoundContract { + if x != nil { + return x.Contract + } + return nil +} + +func (x *ContractKeyFilter) GetFilter() *QueryKeyFilter { + if x != nil { + return x.Filter + } + return nil +} + +func (x *ContractKeyFilter) GetAsValueType() bool { + if x != nil { + return x.AsValueType + } + return false +} + // BindRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.Bind]. type BindRequest struct { state protoimpl.MessageState @@ -517,7 +636,7 @@ type BindRequest struct { func (x *BindRequest) Reset() { *x = BindRequest{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[3] + mi := &file_contract_reader_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -530,7 +649,7 @@ func (x *BindRequest) String() string { func (*BindRequest) ProtoMessage() {} func (x *BindRequest) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[3] + mi := &file_contract_reader_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -543,7 +662,7 @@ func (x *BindRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BindRequest.ProtoReflect.Descriptor instead. func (*BindRequest) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{3} + return file_contract_reader_proto_rawDescGZIP(), []int{5} } func (x *BindRequest) GetBindings() []*BoundContract { @@ -565,7 +684,7 @@ type UnbindRequest struct { func (x *UnbindRequest) Reset() { *x = UnbindRequest{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[4] + mi := &file_contract_reader_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -578,7 +697,7 @@ func (x *UnbindRequest) String() string { func (*UnbindRequest) ProtoMessage() {} func (x *UnbindRequest) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[4] + mi := &file_contract_reader_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -591,7 +710,7 @@ func (x *UnbindRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbindRequest.ProtoReflect.Descriptor instead. func (*UnbindRequest) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{4} + return file_contract_reader_proto_rawDescGZIP(), []int{6} } func (x *UnbindRequest) GetBindings() []*BoundContract { @@ -613,7 +732,7 @@ type GetLatestValueReply struct { func (x *GetLatestValueReply) Reset() { *x = GetLatestValueReply{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[5] + mi := &file_contract_reader_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -626,7 +745,7 @@ func (x *GetLatestValueReply) String() string { func (*GetLatestValueReply) ProtoMessage() {} func (x *GetLatestValueReply) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[5] + mi := &file_contract_reader_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -639,7 +758,7 @@ func (x *GetLatestValueReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestValueReply.ProtoReflect.Descriptor instead. func (*GetLatestValueReply) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{5} + return file_contract_reader_proto_rawDescGZIP(), []int{7} } func (x *GetLatestValueReply) GetRetVal() *VersionedBytes { @@ -662,7 +781,7 @@ type GetLatestValueWithHeadDataReply struct { func (x *GetLatestValueWithHeadDataReply) Reset() { *x = GetLatestValueWithHeadDataReply{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[6] + mi := &file_contract_reader_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -675,7 +794,7 @@ func (x *GetLatestValueWithHeadDataReply) String() string { func (*GetLatestValueWithHeadDataReply) ProtoMessage() {} func (x *GetLatestValueWithHeadDataReply) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[6] + mi := &file_contract_reader_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -688,7 +807,7 @@ func (x *GetLatestValueWithHeadDataReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestValueWithHeadDataReply.ProtoReflect.Descriptor instead. func (*GetLatestValueWithHeadDataReply) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{6} + return file_contract_reader_proto_rawDescGZIP(), []int{8} } func (x *GetLatestValueWithHeadDataReply) GetRetVal() *VersionedBytes { @@ -717,7 +836,7 @@ type BatchGetLatestValuesReply struct { func (x *BatchGetLatestValuesReply) Reset() { *x = BatchGetLatestValuesReply{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[7] + mi := &file_contract_reader_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -730,7 +849,7 @@ func (x *BatchGetLatestValuesReply) String() string { func (*BatchGetLatestValuesReply) ProtoMessage() {} func (x *BatchGetLatestValuesReply) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[7] + mi := &file_contract_reader_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -743,7 +862,7 @@ func (x *BatchGetLatestValuesReply) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchGetLatestValuesReply.ProtoReflect.Descriptor instead. func (*BatchGetLatestValuesReply) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{7} + return file_contract_reader_proto_rawDescGZIP(), []int{9} } func (x *BatchGetLatestValuesReply) GetResults() []*ContractBatchResult { @@ -765,7 +884,7 @@ type QueryKeyReply struct { func (x *QueryKeyReply) Reset() { *x = QueryKeyReply{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[8] + mi := &file_contract_reader_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -778,7 +897,7 @@ func (x *QueryKeyReply) String() string { func (*QueryKeyReply) ProtoMessage() {} func (x *QueryKeyReply) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[8] + mi := &file_contract_reader_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -791,7 +910,7 @@ func (x *QueryKeyReply) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryKeyReply.ProtoReflect.Descriptor instead. func (*QueryKeyReply) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{8} + return file_contract_reader_proto_rawDescGZIP(), []int{10} } func (x *QueryKeyReply) GetSequences() []*Sequence { @@ -801,6 +920,54 @@ func (x *QueryKeyReply) GetSequences() []*Sequence { return nil } +// QueryKeysReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.QueryKeys]. +type QueryKeysReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sequences []*SequenceWithKey `protobuf:"bytes,1,rep,name=sequences,proto3" json:"sequences,omitempty"` +} + +func (x *QueryKeysReply) Reset() { + *x = QueryKeysReply{} + if protoimpl.UnsafeEnabled { + mi := &file_contract_reader_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryKeysReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryKeysReply) ProtoMessage() {} + +func (x *QueryKeysReply) ProtoReflect() protoreflect.Message { + mi := &file_contract_reader_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryKeysReply.ProtoReflect.Descriptor instead. +func (*QueryKeysReply) Descriptor() ([]byte, []int) { + return file_contract_reader_proto_rawDescGZIP(), []int{11} +} + +func (x *QueryKeysReply) GetSequences() []*SequenceWithKey { + if x != nil { + return x.Sequences + } + return nil +} + // ContractBatch is gRPC adapter for the BatchGetLatestValuesRequest struct map value [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.BatchGetLatestValuesRequest]. type ContractBatch struct { state protoimpl.MessageState @@ -814,7 +981,7 @@ type ContractBatch struct { func (x *ContractBatch) Reset() { *x = ContractBatch{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[9] + mi := &file_contract_reader_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -827,7 +994,7 @@ func (x *ContractBatch) String() string { func (*ContractBatch) ProtoMessage() {} func (x *ContractBatch) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[9] + mi := &file_contract_reader_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -840,7 +1007,7 @@ func (x *ContractBatch) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractBatch.ProtoReflect.Descriptor instead. func (*ContractBatch) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{9} + return file_contract_reader_proto_rawDescGZIP(), []int{12} } func (x *ContractBatch) GetContract() *BoundContract { @@ -871,7 +1038,7 @@ type BatchRead struct { func (x *BatchRead) Reset() { *x = BatchRead{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[10] + mi := &file_contract_reader_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -884,7 +1051,7 @@ func (x *BatchRead) String() string { func (*BatchRead) ProtoMessage() {} func (x *BatchRead) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[10] + mi := &file_contract_reader_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -897,7 +1064,7 @@ func (x *BatchRead) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchRead.ProtoReflect.Descriptor instead. func (*BatchRead) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{10} + return file_contract_reader_proto_rawDescGZIP(), []int{13} } func (x *BatchRead) GetReadName() string { @@ -934,7 +1101,7 @@ type ContractBatchResult struct { func (x *ContractBatchResult) Reset() { *x = ContractBatchResult{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[11] + mi := &file_contract_reader_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -947,7 +1114,7 @@ func (x *ContractBatchResult) String() string { func (*ContractBatchResult) ProtoMessage() {} func (x *ContractBatchResult) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[11] + mi := &file_contract_reader_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -960,7 +1127,7 @@ func (x *ContractBatchResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractBatchResult.ProtoReflect.Descriptor instead. func (*ContractBatchResult) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{11} + return file_contract_reader_proto_rawDescGZIP(), []int{14} } func (x *ContractBatchResult) GetContract() *BoundContract { @@ -991,7 +1158,7 @@ type BatchReadResult struct { func (x *BatchReadResult) Reset() { *x = BatchReadResult{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[12] + mi := &file_contract_reader_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1004,7 +1171,7 @@ func (x *BatchReadResult) String() string { func (*BatchReadResult) ProtoMessage() {} func (x *BatchReadResult) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[12] + mi := &file_contract_reader_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1017,7 +1184,7 @@ func (x *BatchReadResult) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchReadResult.ProtoReflect.Descriptor instead. func (*BatchReadResult) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{12} + return file_contract_reader_proto_rawDescGZIP(), []int{15} } func (x *BatchReadResult) GetReadName() string { @@ -1055,7 +1222,7 @@ type Head struct { func (x *Head) Reset() { *x = Head{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[13] + mi := &file_contract_reader_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1068,7 +1235,7 @@ func (x *Head) String() string { func (*Head) ProtoMessage() {} func (x *Head) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[13] + mi := &file_contract_reader_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1081,7 +1248,7 @@ func (x *Head) ProtoReflect() protoreflect.Message { // Deprecated: Use Head.ProtoReflect.Descriptor instead. func (*Head) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{13} + return file_contract_reader_proto_rawDescGZIP(), []int{16} } func (x *Head) GetHeight() string { @@ -1119,7 +1286,7 @@ type Sequence struct { func (x *Sequence) Reset() { *x = Sequence{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[14] + mi := &file_contract_reader_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1132,7 +1299,7 @@ func (x *Sequence) String() string { func (*Sequence) ProtoMessage() {} func (x *Sequence) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[14] + mi := &file_contract_reader_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1145,7 +1312,7 @@ func (x *Sequence) ProtoReflect() protoreflect.Message { // Deprecated: Use Sequence.ProtoReflect.Descriptor instead. func (*Sequence) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{14} + return file_contract_reader_proto_rawDescGZIP(), []int{17} } func (x *Sequence) GetSequenceCursor() string { @@ -1169,6 +1336,77 @@ func (x *Sequence) GetData() *VersionedBytes { return nil } +type SequenceWithKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SequenceCursor string `protobuf:"bytes,1,opt,name=sequence_cursor,json=sequenceCursor,proto3" json:"sequence_cursor,omitempty"` + Head *Head `protobuf:"bytes,2,opt,name=head,proto3" json:"head,omitempty"` + Data *VersionedBytes `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` +} + +func (x *SequenceWithKey) Reset() { + *x = SequenceWithKey{} + if protoimpl.UnsafeEnabled { + mi := &file_contract_reader_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SequenceWithKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SequenceWithKey) ProtoMessage() {} + +func (x *SequenceWithKey) ProtoReflect() protoreflect.Message { + mi := &file_contract_reader_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SequenceWithKey.ProtoReflect.Descriptor instead. +func (*SequenceWithKey) Descriptor() ([]byte, []int) { + return file_contract_reader_proto_rawDescGZIP(), []int{18} +} + +func (x *SequenceWithKey) GetSequenceCursor() string { + if x != nil { + return x.SequenceCursor + } + return "" +} + +func (x *SequenceWithKey) GetHead() *Head { + if x != nil { + return x.Head + } + return nil +} + +func (x *SequenceWithKey) GetData() *VersionedBytes { + if x != nil { + return x.Data + } + return nil +} + +func (x *SequenceWithKey) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + // BoundContract represents a [github.com/smartcontractkit/chainlink-common/pkg/types.BoundContract]. type BoundContract struct { state protoimpl.MessageState @@ -1182,7 +1420,7 @@ type BoundContract struct { func (x *BoundContract) Reset() { *x = BoundContract{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[15] + mi := &file_contract_reader_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1195,7 +1433,7 @@ func (x *BoundContract) String() string { func (*BoundContract) ProtoMessage() {} func (x *BoundContract) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[15] + mi := &file_contract_reader_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1208,7 +1446,7 @@ func (x *BoundContract) ProtoReflect() protoreflect.Message { // Deprecated: Use BoundContract.ProtoReflect.Descriptor instead. func (*BoundContract) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{15} + return file_contract_reader_proto_rawDescGZIP(), []int{19} } func (x *BoundContract) GetAddress() string { @@ -1238,7 +1476,7 @@ type QueryKeyFilter struct { func (x *QueryKeyFilter) Reset() { *x = QueryKeyFilter{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[16] + mi := &file_contract_reader_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1251,7 +1489,7 @@ func (x *QueryKeyFilter) String() string { func (*QueryKeyFilter) ProtoMessage() {} func (x *QueryKeyFilter) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[16] + mi := &file_contract_reader_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1264,7 +1502,7 @@ func (x *QueryKeyFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryKeyFilter.ProtoReflect.Descriptor instead. func (*QueryKeyFilter) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{16} + return file_contract_reader_proto_rawDescGZIP(), []int{20} } func (x *QueryKeyFilter) GetKey() string { @@ -1298,7 +1536,7 @@ type Expression struct { func (x *Expression) Reset() { *x = Expression{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[17] + mi := &file_contract_reader_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1311,7 +1549,7 @@ func (x *Expression) String() string { func (*Expression) ProtoMessage() {} func (x *Expression) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[17] + mi := &file_contract_reader_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1324,7 +1562,7 @@ func (x *Expression) ProtoReflect() protoreflect.Message { // Deprecated: Use Expression.ProtoReflect.Descriptor instead. func (*Expression) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{17} + return file_contract_reader_proto_rawDescGZIP(), []int{21} } func (m *Expression) GetEvaluator() isExpression_Evaluator { @@ -1376,7 +1614,7 @@ type BooleanExpression struct { func (x *BooleanExpression) Reset() { *x = BooleanExpression{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[18] + mi := &file_contract_reader_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1389,7 +1627,7 @@ func (x *BooleanExpression) String() string { func (*BooleanExpression) ProtoMessage() {} func (x *BooleanExpression) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[18] + mi := &file_contract_reader_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1402,7 +1640,7 @@ func (x *BooleanExpression) ProtoReflect() protoreflect.Message { // Deprecated: Use BooleanExpression.ProtoReflect.Descriptor instead. func (*BooleanExpression) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{18} + return file_contract_reader_proto_rawDescGZIP(), []int{22} } func (x *BooleanExpression) GetBooleanOperator() BooleanOperator { @@ -1430,7 +1668,7 @@ type And struct { func (x *And) Reset() { *x = And{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[19] + mi := &file_contract_reader_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1443,7 +1681,7 @@ func (x *And) String() string { func (*And) ProtoMessage() {} func (x *And) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[19] + mi := &file_contract_reader_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1456,7 +1694,7 @@ func (x *And) ProtoReflect() protoreflect.Message { // Deprecated: Use And.ProtoReflect.Descriptor instead. func (*And) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{19} + return file_contract_reader_proto_rawDescGZIP(), []int{23} } func (x *And) GetExpr() []*Expression { @@ -1477,7 +1715,7 @@ type Or struct { func (x *Or) Reset() { *x = Or{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[20] + mi := &file_contract_reader_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1490,7 +1728,7 @@ func (x *Or) String() string { func (*Or) ProtoMessage() {} func (x *Or) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[20] + mi := &file_contract_reader_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1503,7 +1741,7 @@ func (x *Or) ProtoReflect() protoreflect.Message { // Deprecated: Use Or.ProtoReflect.Descriptor instead. func (*Or) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{20} + return file_contract_reader_proto_rawDescGZIP(), []int{24} } func (x *Or) GetExpr() []*Expression { @@ -1525,7 +1763,7 @@ type ValueComparator struct { func (x *ValueComparator) Reset() { *x = ValueComparator{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[21] + mi := &file_contract_reader_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1538,7 +1776,7 @@ func (x *ValueComparator) String() string { func (*ValueComparator) ProtoMessage() {} func (x *ValueComparator) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[21] + mi := &file_contract_reader_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1551,7 +1789,7 @@ func (x *ValueComparator) ProtoReflect() protoreflect.Message { // Deprecated: Use ValueComparator.ProtoReflect.Descriptor instead. func (*ValueComparator) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{21} + return file_contract_reader_proto_rawDescGZIP(), []int{25} } func (x *ValueComparator) GetValue() *VersionedBytes { @@ -1580,7 +1818,7 @@ type Comparator struct { func (x *Comparator) Reset() { *x = Comparator{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[22] + mi := &file_contract_reader_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1593,7 +1831,7 @@ func (x *Comparator) String() string { func (*Comparator) ProtoMessage() {} func (x *Comparator) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[22] + mi := &file_contract_reader_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1606,7 +1844,7 @@ func (x *Comparator) ProtoReflect() protoreflect.Message { // Deprecated: Use Comparator.ProtoReflect.Descriptor instead. func (*Comparator) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{22} + return file_contract_reader_proto_rawDescGZIP(), []int{26} } func (x *Comparator) GetName() string { @@ -1635,7 +1873,7 @@ type Block struct { func (x *Block) Reset() { *x = Block{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[23] + mi := &file_contract_reader_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1648,7 +1886,7 @@ func (x *Block) String() string { func (*Block) ProtoMessage() {} func (x *Block) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[23] + mi := &file_contract_reader_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1661,7 +1899,7 @@ func (x *Block) ProtoReflect() protoreflect.Message { // Deprecated: Use Block.ProtoReflect.Descriptor instead. func (*Block) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{23} + return file_contract_reader_proto_rawDescGZIP(), []int{27} } func (x *Block) GetBlockNumber() string { @@ -1690,7 +1928,7 @@ type Timestamp struct { func (x *Timestamp) Reset() { *x = Timestamp{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[24] + mi := &file_contract_reader_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1703,7 +1941,7 @@ func (x *Timestamp) String() string { func (*Timestamp) ProtoMessage() {} func (x *Timestamp) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[24] + mi := &file_contract_reader_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1716,7 +1954,7 @@ func (x *Timestamp) ProtoReflect() protoreflect.Message { // Deprecated: Use Timestamp.ProtoReflect.Descriptor instead. func (*Timestamp) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{24} + return file_contract_reader_proto_rawDescGZIP(), []int{28} } func (x *Timestamp) GetTimestamp() uint64 { @@ -1744,7 +1982,7 @@ type TxHash struct { func (x *TxHash) Reset() { *x = TxHash{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[25] + mi := &file_contract_reader_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1757,7 +1995,7 @@ func (x *TxHash) String() string { func (*TxHash) ProtoMessage() {} func (x *TxHash) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[25] + mi := &file_contract_reader_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1770,7 +2008,7 @@ func (x *TxHash) ProtoReflect() protoreflect.Message { // Deprecated: Use TxHash.ProtoReflect.Descriptor instead. func (*TxHash) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{25} + return file_contract_reader_proto_rawDescGZIP(), []int{29} } func (x *TxHash) GetTxHash() string { @@ -1799,7 +2037,7 @@ type Primitive struct { func (x *Primitive) Reset() { *x = Primitive{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[26] + mi := &file_contract_reader_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1812,7 +2050,7 @@ func (x *Primitive) String() string { func (*Primitive) ProtoMessage() {} func (x *Primitive) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[26] + mi := &file_contract_reader_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1825,7 +2063,7 @@ func (x *Primitive) ProtoReflect() protoreflect.Message { // Deprecated: Use Primitive.ProtoReflect.Descriptor instead. func (*Primitive) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{26} + return file_contract_reader_proto_rawDescGZIP(), []int{30} } func (m *Primitive) GetPrimitive() isPrimitive_Primitive { @@ -1918,7 +2156,7 @@ type Limit struct { func (x *Limit) Reset() { *x = Limit{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[27] + mi := &file_contract_reader_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1931,7 +2169,7 @@ func (x *Limit) String() string { func (*Limit) ProtoMessage() {} func (x *Limit) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[27] + mi := &file_contract_reader_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1944,7 +2182,7 @@ func (x *Limit) ProtoReflect() protoreflect.Message { // Deprecated: Use Limit.ProtoReflect.Descriptor instead. func (*Limit) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{27} + return file_contract_reader_proto_rawDescGZIP(), []int{31} } func (x *Limit) GetCursor() string { @@ -1980,7 +2218,7 @@ type SortBy struct { func (x *SortBy) Reset() { *x = SortBy{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[28] + mi := &file_contract_reader_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1993,7 +2231,7 @@ func (x *SortBy) String() string { func (*SortBy) ProtoMessage() {} func (x *SortBy) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[28] + mi := &file_contract_reader_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2006,7 +2244,7 @@ func (x *SortBy) ProtoReflect() protoreflect.Message { // Deprecated: Use SortBy.ProtoReflect.Descriptor instead. func (*SortBy) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{28} + return file_contract_reader_proto_rawDescGZIP(), []int{32} } func (x *SortBy) GetSortType() SortType { @@ -2036,7 +2274,7 @@ type LimitAndSort struct { func (x *LimitAndSort) Reset() { *x = LimitAndSort{} if protoimpl.UnsafeEnabled { - mi := &file_contract_reader_proto_msgTypes[29] + mi := &file_contract_reader_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2049,7 +2287,7 @@ func (x *LimitAndSort) String() string { func (*LimitAndSort) ProtoMessage() {} func (x *LimitAndSort) ProtoReflect() protoreflect.Message { - mi := &file_contract_reader_proto_msgTypes[29] + mi := &file_contract_reader_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2062,7 +2300,7 @@ func (x *LimitAndSort) ProtoReflect() protoreflect.Message { // Deprecated: Use LimitAndSort.ProtoReflect.Descriptor instead. func (*LimitAndSort) Descriptor() ([]byte, []int) { - return file_contract_reader_proto_rawDescGZIP(), []int{29} + return file_contract_reader_proto_rawDescGZIP(), []int{33} } func (x *LimitAndSort) GetSortBy() []*SortBy { @@ -2117,230 +2355,266 @@ var file_contract_reader_proto_rawDesc = []byte{ 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x64, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, - 0x3e, 0x0a, 0x0b, 0x42, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, - 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, - 0x40, 0x0a, 0x0d, 0x55, 0x6e, 0x62, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x2f, 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x73, 0x22, 0x44, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2d, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x5f, - 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, - 0x06, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x22, 0x79, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, - 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2d, 0x0a, 0x07, 0x72, 0x65, - 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, - 0x73, 0x52, 0x06, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x12, 0x27, 0x0a, 0x09, 0x68, 0x65, 0x61, - 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x44, 0x61, - 0x74, 0x61, 0x22, 0x50, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x33, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x73, 0x22, 0x3d, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2c, 0x0a, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x65, 0x73, 0x22, 0x67, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x12, 0x2f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, - 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x52, 0x65, 0x61, 0x64, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x22, 0x8b, 0x01, 0x0a, - 0x09, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, - 0x61, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, - 0x65, 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, - 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, - 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x22, 0x77, 0x0a, 0x13, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x73, 0x22, 0x79, 0x0a, 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x76, 0x61, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x09, 0x72, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x50, - 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x22, 0x7d, 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x43, - 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, - 0x04, 0x68, 0x65, 0x61, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, - 0x3d, 0x0a, 0x0d, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x54, - 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x30, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x94, 0x01, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x50, 0x72, - 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, - 0x74, 0x69, 0x76, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x5f, - 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x45, - 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x11, 0x62, 0x6f, 0x6f, - 0x6c, 0x65, 0x61, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0b, - 0x0a, 0x09, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x87, 0x01, 0x0a, 0x11, - 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x40, 0x0a, 0x10, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x52, 0x0f, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, - 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x2b, 0x0a, 0x03, 0x41, 0x6e, 0x64, 0x12, 0x24, 0x0a, 0x04, - 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x65, 0x78, - 0x70, 0x72, 0x22, 0x2a, 0x0a, 0x02, 0x4f, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x22, 0x73, - 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, - 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, - 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x22, 0x64, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x6f, - 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x60, 0x0a, 0x05, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, - 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x5f, 0x0a, 0x09, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x21, 0x0a, 0x06, - 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, - 0xff, 0x01, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x32, 0x0a, - 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x12, 0x23, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x00, 0x52, - 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x07, 0x74, - 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x06, 0x74, 0x78, - 0x48, 0x61, 0x73, 0x68, 0x42, 0x0b, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x22, 0x8d, 0x01, 0x0a, 0x05, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x63, - 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, - 0x75, 0x72, 0x73, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x88, - 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x75, 0x72, - 0x73, 0x6f, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0x68, 0x0a, 0x06, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x2b, 0x0a, 0x09, 0x73, - 0x6f, 0x72, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, - 0x73, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x58, 0x0a, 0x0c, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x64, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x25, 0x0a, 0x07, 0x73, - 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, - 0x42, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2a, 0x47, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, - 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x45, - 0x71, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x65, 0x71, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, - 0x47, 0x74, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x4c, 0x74, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, - 0x47, 0x74, 0x65, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x74, 0x65, 0x10, 0x05, 0x2a, 0x22, - 0x0a, 0x0f, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, - 0x72, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x52, - 0x10, 0x01, 0x2a, 0x2c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, - 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x10, - 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x10, 0x01, - 0x2a, 0x2f, 0x0a, 0x0f, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x69, 0x6e, 0x67, - 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x10, - 0x01, 0x2a, 0x22, 0x0a, 0x0d, 0x53, 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x73, 0x63, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, - 0x65, 0x73, 0x63, 0x10, 0x01, 0x2a, 0x3e, 0x0a, 0x08, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x65, 0x10, 0x02, 0x32, 0xc6, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, - 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, + 0x7f, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x0e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, + 0x61, 0x6e, 0x64, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x64, 0x53, 0x6f, + 0x72, 0x74, 0x52, 0x0c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x64, 0x53, 0x6f, 0x72, 0x74, + 0x22, 0x96, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4b, 0x65, 0x79, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x73, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3e, 0x0a, 0x0b, 0x42, 0x69, 0x6e, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, + 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x40, 0x0a, 0x0d, 0x55, 0x6e, 0x62, + 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, 0x64, 0x44, 0x61, - 0x74, 0x61, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x14, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, - 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, - 0x65, 0x79, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, - 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x33, 0x0a, 0x04, 0x42, 0x69, 0x6e, 0x64, 0x12, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x42, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6c, 0x79, 0x12, 0x2d, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x72, 0x65, 0x74, 0x56, 0x61, + 0x6c, 0x22, 0x79, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x57, 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2d, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x72, 0x65, 0x74, + 0x56, 0x61, 0x6c, 0x12, 0x27, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, + 0x61, 0x64, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x50, 0x0a, 0x19, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x3d, + 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x2c, 0x0a, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x52, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x45, 0x0a, + 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x33, 0x0a, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x57, 0x69, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x22, 0x67, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, + 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x73, 0x22, 0x8b, 0x01, + 0x0a, 0x09, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, + 0x65, 0x61, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x72, 0x65, 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x5f, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x52, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x22, 0x77, 0x0a, 0x13, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x75, 0x6e, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x22, 0x79, 0x0a, 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x76, + 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x09, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x56, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, + 0x50, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x22, 0x7d, 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, + 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x04, 0x68, 0x65, 0x61, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x96, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x57, 0x69, 0x74, + 0x68, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x1e, 0x0a, + 0x04, 0x68, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x68, 0x65, 0x61, 0x64, 0x12, 0x28, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x3d, 0x0a, 0x0d, 0x42, 0x6f, 0x75, + 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x0a, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x94, + 0x01, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, + 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x48, + 0x0a, 0x12, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x11, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x65, 0x76, 0x61, 0x6c, + 0x75, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x87, 0x01, 0x0a, 0x11, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, + 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10, 0x62, + 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x6f, 0x6f, + 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0f, 0x62, 0x6f, + 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, + 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x2b, 0x0a, 0x03, 0x41, 0x6e, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x22, 0x2a, 0x0a, 0x02, + 0x4f, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x22, 0x73, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x64, 0x0a, + 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x42, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x22, 0x60, 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x21, 0x0a, 0x0c, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x34, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x5f, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x69, 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x21, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x17, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0xff, 0x01, 0x0a, 0x09, 0x50, 0x72, + 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x00, 0x52, + 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, + 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x78, + 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x42, 0x0b, + 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0x8d, 0x01, 0x0a, 0x05, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x88, + 0x01, 0x01, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x75, 0x72, + 0x73, 0x6f, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x09, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x42, 0x0c, 0x0a, + 0x0a, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x06, 0x53, + 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x2b, 0x0a, 0x09, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x6f, 0x72, + 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x58, 0x0a, 0x0c, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, + 0x64, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x25, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x6f, + 0x72, 0x74, 0x42, 0x79, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x21, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2a, + 0x47, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x45, 0x71, 0x10, 0x00, 0x12, 0x07, 0x0a, + 0x03, 0x4e, 0x65, 0x71, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x47, 0x74, 0x10, 0x02, 0x12, 0x06, + 0x0a, 0x02, 0x4c, 0x74, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x74, 0x65, 0x10, 0x04, 0x12, + 0x07, 0x0a, 0x03, 0x4c, 0x74, 0x65, 0x10, 0x05, 0x2a, 0x22, 0x0a, 0x0f, 0x42, 0x6f, 0x6f, 0x6c, + 0x65, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x07, 0x0a, 0x03, 0x41, + 0x4e, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x52, 0x10, 0x01, 0x2a, 0x2c, 0x0a, 0x0a, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x10, 0x01, 0x2a, 0x2f, 0x0a, 0x0f, 0x43, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, + 0x09, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, + 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x10, 0x01, 0x2a, 0x22, 0x0a, 0x0d, 0x53, + 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x07, 0x0a, 0x03, + 0x41, 0x73, 0x63, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x65, 0x73, 0x63, 0x10, 0x01, 0x2a, + 0x3e, 0x0a, 0x08, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x53, + 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x10, 0x00, 0x12, 0x0d, + 0x0a, 0x09, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x10, 0x0a, + 0x0c, 0x53, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x02, 0x32, + 0x83, 0x04, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x62, + 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x57, 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x57, + 0x69, 0x74, 0x68, 0x48, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x14, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x38, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x42, 0x69, 0x6e, 0x64, 0x12, + 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, + 0x55, 0x6e, 0x62, 0x69, 0x6e, 0x64, 0x12, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x55, 0x6e, + 0x62, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x6e, 0x62, 0x69, 0x6e, 0x64, 0x12, - 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x55, 0x6e, 0x62, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x43, - 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, - 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -2356,7 +2630,7 @@ func file_contract_reader_proto_rawDescGZIP() []byte { } var file_contract_reader_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_contract_reader_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_contract_reader_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_contract_reader_proto_goTypes = []interface{}{ (ComparisonOperator)(0), // 0: loop.ComparisonOperator (BooleanOperator)(0), // 1: loop.BooleanOperator @@ -2367,98 +2641,111 @@ var file_contract_reader_proto_goTypes = []interface{}{ (*GetLatestValueRequest)(nil), // 6: loop.GetLatestValueRequest (*BatchGetLatestValuesRequest)(nil), // 7: loop.BatchGetLatestValuesRequest (*QueryKeyRequest)(nil), // 8: loop.QueryKeyRequest - (*BindRequest)(nil), // 9: loop.BindRequest - (*UnbindRequest)(nil), // 10: loop.UnbindRequest - (*GetLatestValueReply)(nil), // 11: loop.GetLatestValueReply - (*GetLatestValueWithHeadDataReply)(nil), // 12: loop.GetLatestValueWithHeadDataReply - (*BatchGetLatestValuesReply)(nil), // 13: loop.BatchGetLatestValuesReply - (*QueryKeyReply)(nil), // 14: loop.QueryKeyReply - (*ContractBatch)(nil), // 15: loop.ContractBatch - (*BatchRead)(nil), // 16: loop.BatchRead - (*ContractBatchResult)(nil), // 17: loop.ContractBatchResult - (*BatchReadResult)(nil), // 18: loop.BatchReadResult - (*Head)(nil), // 19: loop.Head - (*Sequence)(nil), // 20: loop.Sequence - (*BoundContract)(nil), // 21: loop.BoundContract - (*QueryKeyFilter)(nil), // 22: loop.QueryKeyFilter - (*Expression)(nil), // 23: loop.Expression - (*BooleanExpression)(nil), // 24: loop.BooleanExpression - (*And)(nil), // 25: loop.And - (*Or)(nil), // 26: loop.Or - (*ValueComparator)(nil), // 27: loop.ValueComparator - (*Comparator)(nil), // 28: loop.Comparator - (*Block)(nil), // 29: loop.Block - (*Timestamp)(nil), // 30: loop.Timestamp - (*TxHash)(nil), // 31: loop.TxHash - (*Primitive)(nil), // 32: loop.Primitive - (*Limit)(nil), // 33: loop.Limit - (*SortBy)(nil), // 34: loop.SortBy - (*LimitAndSort)(nil), // 35: loop.LimitAndSort - (*VersionedBytes)(nil), // 36: loop.VersionedBytes - (*emptypb.Empty)(nil), // 37: google.protobuf.Empty + (*QueryKeysRequest)(nil), // 9: loop.QueryKeysRequest + (*ContractKeyFilter)(nil), // 10: loop.ContractKeyFilter + (*BindRequest)(nil), // 11: loop.BindRequest + (*UnbindRequest)(nil), // 12: loop.UnbindRequest + (*GetLatestValueReply)(nil), // 13: loop.GetLatestValueReply + (*GetLatestValueWithHeadDataReply)(nil), // 14: loop.GetLatestValueWithHeadDataReply + (*BatchGetLatestValuesReply)(nil), // 15: loop.BatchGetLatestValuesReply + (*QueryKeyReply)(nil), // 16: loop.QueryKeyReply + (*QueryKeysReply)(nil), // 17: loop.QueryKeysReply + (*ContractBatch)(nil), // 18: loop.ContractBatch + (*BatchRead)(nil), // 19: loop.BatchRead + (*ContractBatchResult)(nil), // 20: loop.ContractBatchResult + (*BatchReadResult)(nil), // 21: loop.BatchReadResult + (*Head)(nil), // 22: loop.Head + (*Sequence)(nil), // 23: loop.Sequence + (*SequenceWithKey)(nil), // 24: loop.SequenceWithKey + (*BoundContract)(nil), // 25: loop.BoundContract + (*QueryKeyFilter)(nil), // 26: loop.QueryKeyFilter + (*Expression)(nil), // 27: loop.Expression + (*BooleanExpression)(nil), // 28: loop.BooleanExpression + (*And)(nil), // 29: loop.And + (*Or)(nil), // 30: loop.Or + (*ValueComparator)(nil), // 31: loop.ValueComparator + (*Comparator)(nil), // 32: loop.Comparator + (*Block)(nil), // 33: loop.Block + (*Timestamp)(nil), // 34: loop.Timestamp + (*TxHash)(nil), // 35: loop.TxHash + (*Primitive)(nil), // 36: loop.Primitive + (*Limit)(nil), // 37: loop.Limit + (*SortBy)(nil), // 38: loop.SortBy + (*LimitAndSort)(nil), // 39: loop.LimitAndSort + (*VersionedBytes)(nil), // 40: loop.VersionedBytes + (*emptypb.Empty)(nil), // 41: google.protobuf.Empty } var file_contract_reader_proto_depIdxs = []int32{ 2, // 0: loop.GetLatestValueRequest.confidence:type_name -> loop.Confidence - 36, // 1: loop.GetLatestValueRequest.params:type_name -> loop.VersionedBytes - 15, // 2: loop.BatchGetLatestValuesRequest.requests:type_name -> loop.ContractBatch - 21, // 3: loop.QueryKeyRequest.contract:type_name -> loop.BoundContract - 22, // 4: loop.QueryKeyRequest.filter:type_name -> loop.QueryKeyFilter - 35, // 5: loop.QueryKeyRequest.limit_and_sort:type_name -> loop.LimitAndSort - 21, // 6: loop.BindRequest.bindings:type_name -> loop.BoundContract - 21, // 7: loop.UnbindRequest.bindings:type_name -> loop.BoundContract - 36, // 8: loop.GetLatestValueReply.ret_val:type_name -> loop.VersionedBytes - 36, // 9: loop.GetLatestValueWithHeadDataReply.ret_val:type_name -> loop.VersionedBytes - 19, // 10: loop.GetLatestValueWithHeadDataReply.head_data:type_name -> loop.Head - 17, // 11: loop.BatchGetLatestValuesReply.results:type_name -> loop.ContractBatchResult - 20, // 12: loop.QueryKeyReply.sequences:type_name -> loop.Sequence - 21, // 13: loop.ContractBatch.contract:type_name -> loop.BoundContract - 16, // 14: loop.ContractBatch.reads:type_name -> loop.BatchRead - 36, // 15: loop.BatchRead.params:type_name -> loop.VersionedBytes - 36, // 16: loop.BatchRead.return_val:type_name -> loop.VersionedBytes - 21, // 17: loop.ContractBatchResult.contract:type_name -> loop.BoundContract - 18, // 18: loop.ContractBatchResult.results:type_name -> loop.BatchReadResult - 36, // 19: loop.BatchReadResult.return_val:type_name -> loop.VersionedBytes - 19, // 20: loop.Sequence.head:type_name -> loop.Head - 36, // 21: loop.Sequence.data:type_name -> loop.VersionedBytes - 23, // 22: loop.QueryKeyFilter.expression:type_name -> loop.Expression - 32, // 23: loop.Expression.primitive:type_name -> loop.Primitive - 24, // 24: loop.Expression.boolean_expression:type_name -> loop.BooleanExpression - 1, // 25: loop.BooleanExpression.boolean_operator:type_name -> loop.BooleanOperator - 23, // 26: loop.BooleanExpression.expression:type_name -> loop.Expression - 23, // 27: loop.And.expr:type_name -> loop.Expression - 23, // 28: loop.Or.expr:type_name -> loop.Expression - 36, // 29: loop.ValueComparator.value:type_name -> loop.VersionedBytes - 0, // 30: loop.ValueComparator.operator:type_name -> loop.ComparisonOperator - 27, // 31: loop.Comparator.value_comparators:type_name -> loop.ValueComparator - 0, // 32: loop.Block.operator:type_name -> loop.ComparisonOperator - 0, // 33: loop.Timestamp.operator:type_name -> loop.ComparisonOperator - 28, // 34: loop.Primitive.comparator:type_name -> loop.Comparator - 29, // 35: loop.Primitive.block:type_name -> loop.Block - 2, // 36: loop.Primitive.confidence:type_name -> loop.Confidence - 30, // 37: loop.Primitive.timestamp:type_name -> loop.Timestamp - 31, // 38: loop.Primitive.tx_hash:type_name -> loop.TxHash - 3, // 39: loop.Limit.direction:type_name -> loop.CursorDirection - 5, // 40: loop.SortBy.sort_type:type_name -> loop.SortType - 4, // 41: loop.SortBy.direction:type_name -> loop.SortDirection - 34, // 42: loop.LimitAndSort.sort_by:type_name -> loop.SortBy - 33, // 43: loop.LimitAndSort.limit:type_name -> loop.Limit - 6, // 44: loop.ContractReader.GetLatestValue:input_type -> loop.GetLatestValueRequest - 6, // 45: loop.ContractReader.GetLatestValueWithHeadData:input_type -> loop.GetLatestValueRequest - 7, // 46: loop.ContractReader.BatchGetLatestValues:input_type -> loop.BatchGetLatestValuesRequest - 8, // 47: loop.ContractReader.QueryKey:input_type -> loop.QueryKeyRequest - 9, // 48: loop.ContractReader.Bind:input_type -> loop.BindRequest - 10, // 49: loop.ContractReader.Unbind:input_type -> loop.UnbindRequest - 11, // 50: loop.ContractReader.GetLatestValue:output_type -> loop.GetLatestValueReply - 12, // 51: loop.ContractReader.GetLatestValueWithHeadData:output_type -> loop.GetLatestValueWithHeadDataReply - 13, // 52: loop.ContractReader.BatchGetLatestValues:output_type -> loop.BatchGetLatestValuesReply - 14, // 53: loop.ContractReader.QueryKey:output_type -> loop.QueryKeyReply - 37, // 54: loop.ContractReader.Bind:output_type -> google.protobuf.Empty - 37, // 55: loop.ContractReader.Unbind:output_type -> google.protobuf.Empty - 50, // [50:56] is the sub-list for method output_type - 44, // [44:50] is the sub-list for method input_type - 44, // [44:44] is the sub-list for extension type_name - 44, // [44:44] is the sub-list for extension extendee - 0, // [0:44] is the sub-list for field type_name + 40, // 1: loop.GetLatestValueRequest.params:type_name -> loop.VersionedBytes + 18, // 2: loop.BatchGetLatestValuesRequest.requests:type_name -> loop.ContractBatch + 25, // 3: loop.QueryKeyRequest.contract:type_name -> loop.BoundContract + 26, // 4: loop.QueryKeyRequest.filter:type_name -> loop.QueryKeyFilter + 39, // 5: loop.QueryKeyRequest.limit_and_sort:type_name -> loop.LimitAndSort + 10, // 6: loop.QueryKeysRequest.filters:type_name -> loop.ContractKeyFilter + 39, // 7: loop.QueryKeysRequest.limit_and_sort:type_name -> loop.LimitAndSort + 25, // 8: loop.ContractKeyFilter.contract:type_name -> loop.BoundContract + 26, // 9: loop.ContractKeyFilter.filter:type_name -> loop.QueryKeyFilter + 25, // 10: loop.BindRequest.bindings:type_name -> loop.BoundContract + 25, // 11: loop.UnbindRequest.bindings:type_name -> loop.BoundContract + 40, // 12: loop.GetLatestValueReply.ret_val:type_name -> loop.VersionedBytes + 40, // 13: loop.GetLatestValueWithHeadDataReply.ret_val:type_name -> loop.VersionedBytes + 22, // 14: loop.GetLatestValueWithHeadDataReply.head_data:type_name -> loop.Head + 20, // 15: loop.BatchGetLatestValuesReply.results:type_name -> loop.ContractBatchResult + 23, // 16: loop.QueryKeyReply.sequences:type_name -> loop.Sequence + 24, // 17: loop.QueryKeysReply.sequences:type_name -> loop.SequenceWithKey + 25, // 18: loop.ContractBatch.contract:type_name -> loop.BoundContract + 19, // 19: loop.ContractBatch.reads:type_name -> loop.BatchRead + 40, // 20: loop.BatchRead.params:type_name -> loop.VersionedBytes + 40, // 21: loop.BatchRead.return_val:type_name -> loop.VersionedBytes + 25, // 22: loop.ContractBatchResult.contract:type_name -> loop.BoundContract + 21, // 23: loop.ContractBatchResult.results:type_name -> loop.BatchReadResult + 40, // 24: loop.BatchReadResult.return_val:type_name -> loop.VersionedBytes + 22, // 25: loop.Sequence.head:type_name -> loop.Head + 40, // 26: loop.Sequence.data:type_name -> loop.VersionedBytes + 22, // 27: loop.SequenceWithKey.head:type_name -> loop.Head + 40, // 28: loop.SequenceWithKey.data:type_name -> loop.VersionedBytes + 27, // 29: loop.QueryKeyFilter.expression:type_name -> loop.Expression + 36, // 30: loop.Expression.primitive:type_name -> loop.Primitive + 28, // 31: loop.Expression.boolean_expression:type_name -> loop.BooleanExpression + 1, // 32: loop.BooleanExpression.boolean_operator:type_name -> loop.BooleanOperator + 27, // 33: loop.BooleanExpression.expression:type_name -> loop.Expression + 27, // 34: loop.And.expr:type_name -> loop.Expression + 27, // 35: loop.Or.expr:type_name -> loop.Expression + 40, // 36: loop.ValueComparator.value:type_name -> loop.VersionedBytes + 0, // 37: loop.ValueComparator.operator:type_name -> loop.ComparisonOperator + 31, // 38: loop.Comparator.value_comparators:type_name -> loop.ValueComparator + 0, // 39: loop.Block.operator:type_name -> loop.ComparisonOperator + 0, // 40: loop.Timestamp.operator:type_name -> loop.ComparisonOperator + 32, // 41: loop.Primitive.comparator:type_name -> loop.Comparator + 33, // 42: loop.Primitive.block:type_name -> loop.Block + 2, // 43: loop.Primitive.confidence:type_name -> loop.Confidence + 34, // 44: loop.Primitive.timestamp:type_name -> loop.Timestamp + 35, // 45: loop.Primitive.tx_hash:type_name -> loop.TxHash + 3, // 46: loop.Limit.direction:type_name -> loop.CursorDirection + 5, // 47: loop.SortBy.sort_type:type_name -> loop.SortType + 4, // 48: loop.SortBy.direction:type_name -> loop.SortDirection + 38, // 49: loop.LimitAndSort.sort_by:type_name -> loop.SortBy + 37, // 50: loop.LimitAndSort.limit:type_name -> loop.Limit + 6, // 51: loop.ContractReader.GetLatestValue:input_type -> loop.GetLatestValueRequest + 6, // 52: loop.ContractReader.GetLatestValueWithHeadData:input_type -> loop.GetLatestValueRequest + 7, // 53: loop.ContractReader.BatchGetLatestValues:input_type -> loop.BatchGetLatestValuesRequest + 8, // 54: loop.ContractReader.QueryKey:input_type -> loop.QueryKeyRequest + 9, // 55: loop.ContractReader.QueryKeys:input_type -> loop.QueryKeysRequest + 11, // 56: loop.ContractReader.Bind:input_type -> loop.BindRequest + 12, // 57: loop.ContractReader.Unbind:input_type -> loop.UnbindRequest + 13, // 58: loop.ContractReader.GetLatestValue:output_type -> loop.GetLatestValueReply + 14, // 59: loop.ContractReader.GetLatestValueWithHeadData:output_type -> loop.GetLatestValueWithHeadDataReply + 15, // 60: loop.ContractReader.BatchGetLatestValues:output_type -> loop.BatchGetLatestValuesReply + 16, // 61: loop.ContractReader.QueryKey:output_type -> loop.QueryKeyReply + 17, // 62: loop.ContractReader.QueryKeys:output_type -> loop.QueryKeysReply + 41, // 63: loop.ContractReader.Bind:output_type -> google.protobuf.Empty + 41, // 64: loop.ContractReader.Unbind:output_type -> google.protobuf.Empty + 58, // [58:65] is the sub-list for method output_type + 51, // [51:58] is the sub-list for method input_type + 51, // [51:51] is the sub-list for extension type_name + 51, // [51:51] is the sub-list for extension extendee + 0, // [0:51] is the sub-list for field type_name } func init() { file_contract_reader_proto_init() } @@ -2505,7 +2792,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BindRequest); i { + switch v := v.(*QueryKeysRequest); i { case 0: return &v.state case 1: @@ -2517,7 +2804,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnbindRequest); i { + switch v := v.(*ContractKeyFilter); i { case 0: return &v.state case 1: @@ -2529,7 +2816,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetLatestValueReply); i { + switch v := v.(*BindRequest); i { case 0: return &v.state case 1: @@ -2541,7 +2828,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetLatestValueWithHeadDataReply); i { + switch v := v.(*UnbindRequest); i { case 0: return &v.state case 1: @@ -2553,7 +2840,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchGetLatestValuesReply); i { + switch v := v.(*GetLatestValueReply); i { case 0: return &v.state case 1: @@ -2565,7 +2852,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryKeyReply); i { + switch v := v.(*GetLatestValueWithHeadDataReply); i { case 0: return &v.state case 1: @@ -2577,7 +2864,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContractBatch); i { + switch v := v.(*BatchGetLatestValuesReply); i { case 0: return &v.state case 1: @@ -2589,7 +2876,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchRead); i { + switch v := v.(*QueryKeyReply); i { case 0: return &v.state case 1: @@ -2601,7 +2888,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContractBatchResult); i { + switch v := v.(*QueryKeysReply); i { case 0: return &v.state case 1: @@ -2613,7 +2900,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchReadResult); i { + switch v := v.(*ContractBatch); i { case 0: return &v.state case 1: @@ -2625,7 +2912,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Head); i { + switch v := v.(*BatchRead); i { case 0: return &v.state case 1: @@ -2637,7 +2924,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Sequence); i { + switch v := v.(*ContractBatchResult); i { case 0: return &v.state case 1: @@ -2649,7 +2936,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BoundContract); i { + switch v := v.(*BatchReadResult); i { case 0: return &v.state case 1: @@ -2661,7 +2948,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryKeyFilter); i { + switch v := v.(*Head); i { case 0: return &v.state case 1: @@ -2673,7 +2960,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Expression); i { + switch v := v.(*Sequence); i { case 0: return &v.state case 1: @@ -2685,7 +2972,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BooleanExpression); i { + switch v := v.(*SequenceWithKey); i { case 0: return &v.state case 1: @@ -2697,7 +2984,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*And); i { + switch v := v.(*BoundContract); i { case 0: return &v.state case 1: @@ -2709,7 +2996,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Or); i { + switch v := v.(*QueryKeyFilter); i { case 0: return &v.state case 1: @@ -2721,7 +3008,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValueComparator); i { + switch v := v.(*Expression); i { case 0: return &v.state case 1: @@ -2733,7 +3020,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Comparator); i { + switch v := v.(*BooleanExpression); i { case 0: return &v.state case 1: @@ -2745,7 +3032,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Block); i { + switch v := v.(*And); i { case 0: return &v.state case 1: @@ -2757,7 +3044,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Timestamp); i { + switch v := v.(*Or); i { case 0: return &v.state case 1: @@ -2769,7 +3056,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TxHash); i { + switch v := v.(*ValueComparator); i { case 0: return &v.state case 1: @@ -2781,7 +3068,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Primitive); i { + switch v := v.(*Comparator); i { case 0: return &v.state case 1: @@ -2793,7 +3080,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Limit); i { + switch v := v.(*Block); i { case 0: return &v.state case 1: @@ -2805,7 +3092,7 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SortBy); i { + switch v := v.(*Timestamp); i { case 0: return &v.state case 1: @@ -2817,6 +3104,54 @@ func file_contract_reader_proto_init() { } } file_contract_reader_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TxHash); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_contract_reader_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Primitive); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_contract_reader_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Limit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_contract_reader_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SortBy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_contract_reader_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LimitAndSort); i { case 0: return &v.state @@ -2829,25 +3164,25 @@ func file_contract_reader_proto_init() { } } } - file_contract_reader_proto_msgTypes[17].OneofWrappers = []interface{}{ + file_contract_reader_proto_msgTypes[21].OneofWrappers = []interface{}{ (*Expression_Primitive)(nil), (*Expression_BooleanExpression)(nil), } - file_contract_reader_proto_msgTypes[26].OneofWrappers = []interface{}{ + file_contract_reader_proto_msgTypes[30].OneofWrappers = []interface{}{ (*Primitive_Comparator)(nil), (*Primitive_Block)(nil), (*Primitive_Confidence)(nil), (*Primitive_Timestamp)(nil), (*Primitive_TxHash)(nil), } - file_contract_reader_proto_msgTypes[27].OneofWrappers = []interface{}{} + file_contract_reader_proto_msgTypes[31].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_contract_reader_proto_rawDesc, NumEnums: 6, - NumMessages: 30, + NumMessages: 34, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/loop/internal/pb/contract_reader.proto b/pkg/loop/internal/pb/contract_reader.proto index 0205f6a2a..8987c0086 100644 --- a/pkg/loop/internal/pb/contract_reader.proto +++ b/pkg/loop/internal/pb/contract_reader.proto @@ -12,6 +12,7 @@ service ContractReader { rpc GetLatestValueWithHeadData (GetLatestValueRequest) returns (GetLatestValueWithHeadDataReply) {} rpc BatchGetLatestValues (BatchGetLatestValuesRequest) returns (BatchGetLatestValuesReply) {} rpc QueryKey(QueryKeyRequest) returns (QueryKeyReply) {} + rpc QueryKeys(QueryKeysRequest) returns (QueryKeysReply) {} rpc Bind(BindRequest) returns (google.protobuf.Empty) {} rpc Unbind(UnbindRequest) returns (google.protobuf.Empty) {} } @@ -37,6 +38,18 @@ message QueryKeyRequest { bool as_value_type = 4; } +// QueryKeysRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.QueryKeys]. +message QueryKeysRequest { + repeated ContractKeyFilter filters = 1; + LimitAndSort limit_and_sort = 2; +} + +message ContractKeyFilter { + BoundContract contract = 1; + QueryKeyFilter filter = 2; + bool as_value_type = 4; +} + // BindRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.Bind]. message BindRequest { repeated BoundContract bindings = 1; @@ -69,6 +82,11 @@ message QueryKeyReply { repeated Sequence sequences = 1; } +// QueryKeysReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.QueryKeys]. +message QueryKeysReply { + repeated SequenceWithKey sequences = 1; +} + // ContractBatch is gRPC adapter for the BatchGetLatestValuesRequest struct map value [github.com/smartcontractkit/chainlink-common/pkg/types.ContractReader.BatchGetLatestValuesRequest]. message ContractBatch { BoundContract contract = 1; @@ -109,6 +127,13 @@ message Sequence { VersionedBytes data = 3; } +message SequenceWithKey { + string sequence_cursor = 1; + Head head = 2; + VersionedBytes data = 3; + string key = 4; +} + // BoundContract represents a [github.com/smartcontractkit/chainlink-common/pkg/types.BoundContract]. message BoundContract { string address = 1; diff --git a/pkg/loop/internal/pb/contract_reader_grpc.pb.go b/pkg/loop/internal/pb/contract_reader_grpc.pb.go index 1c26fd57a..c8f8d5414 100644 --- a/pkg/loop/internal/pb/contract_reader_grpc.pb.go +++ b/pkg/loop/internal/pb/contract_reader_grpc.pb.go @@ -24,6 +24,7 @@ const ( ContractReader_GetLatestValueWithHeadData_FullMethodName = "/loop.ContractReader/GetLatestValueWithHeadData" ContractReader_BatchGetLatestValues_FullMethodName = "/loop.ContractReader/BatchGetLatestValues" ContractReader_QueryKey_FullMethodName = "/loop.ContractReader/QueryKey" + ContractReader_QueryKeys_FullMethodName = "/loop.ContractReader/QueryKeys" ContractReader_Bind_FullMethodName = "/loop.ContractReader/Bind" ContractReader_Unbind_FullMethodName = "/loop.ContractReader/Unbind" ) @@ -36,6 +37,7 @@ type ContractReaderClient interface { GetLatestValueWithHeadData(ctx context.Context, in *GetLatestValueRequest, opts ...grpc.CallOption) (*GetLatestValueWithHeadDataReply, error) BatchGetLatestValues(ctx context.Context, in *BatchGetLatestValuesRequest, opts ...grpc.CallOption) (*BatchGetLatestValuesReply, error) QueryKey(ctx context.Context, in *QueryKeyRequest, opts ...grpc.CallOption) (*QueryKeyReply, error) + QueryKeys(ctx context.Context, in *QueryKeysRequest, opts ...grpc.CallOption) (*QueryKeysReply, error) Bind(ctx context.Context, in *BindRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) Unbind(ctx context.Context, in *UnbindRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) } @@ -84,6 +86,15 @@ func (c *contractReaderClient) QueryKey(ctx context.Context, in *QueryKeyRequest return out, nil } +func (c *contractReaderClient) QueryKeys(ctx context.Context, in *QueryKeysRequest, opts ...grpc.CallOption) (*QueryKeysReply, error) { + out := new(QueryKeysReply) + err := c.cc.Invoke(ctx, ContractReader_QueryKeys_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *contractReaderClient) Bind(ctx context.Context, in *BindRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) err := c.cc.Invoke(ctx, ContractReader_Bind_FullMethodName, in, out, opts...) @@ -110,6 +121,7 @@ type ContractReaderServer interface { GetLatestValueWithHeadData(context.Context, *GetLatestValueRequest) (*GetLatestValueWithHeadDataReply, error) BatchGetLatestValues(context.Context, *BatchGetLatestValuesRequest) (*BatchGetLatestValuesReply, error) QueryKey(context.Context, *QueryKeyRequest) (*QueryKeyReply, error) + QueryKeys(context.Context, *QueryKeysRequest) (*QueryKeysReply, error) Bind(context.Context, *BindRequest) (*emptypb.Empty, error) Unbind(context.Context, *UnbindRequest) (*emptypb.Empty, error) mustEmbedUnimplementedContractReaderServer() @@ -131,6 +143,9 @@ func (UnimplementedContractReaderServer) BatchGetLatestValues(context.Context, * func (UnimplementedContractReaderServer) QueryKey(context.Context, *QueryKeyRequest) (*QueryKeyReply, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryKey not implemented") } +func (UnimplementedContractReaderServer) QueryKeys(context.Context, *QueryKeysRequest) (*QueryKeysReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryKeys not implemented") +} func (UnimplementedContractReaderServer) Bind(context.Context, *BindRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Bind not implemented") } @@ -222,6 +237,24 @@ func _ContractReader_QueryKey_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _ContractReader_QueryKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryKeysRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ContractReaderServer).QueryKeys(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ContractReader_QueryKeys_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ContractReaderServer).QueryKeys(ctx, req.(*QueryKeysRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _ContractReader_Bind_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(BindRequest) if err := dec(in); err != nil { @@ -281,6 +314,10 @@ var ContractReader_ServiceDesc = grpc.ServiceDesc{ MethodName: "QueryKey", Handler: _ContractReader_QueryKey_Handler, }, + { + MethodName: "QueryKeys", + Handler: _ContractReader_QueryKeys_Handler, + }, { MethodName: "Bind", Handler: _ContractReader_Bind_Handler, diff --git a/pkg/loop/internal/pb/chain_writer.pb.go b/pkg/loop/internal/pb/contract_writer.pb.go similarity index 55% rename from pkg/loop/internal/pb/chain_writer.pb.go rename to pkg/loop/internal/pb/contract_writer.pb.go index df8b7f7a2..b43891cb2 100644 --- a/pkg/loop/internal/pb/chain_writer.pb.go +++ b/pkg/loop/internal/pb/contract_writer.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.31.0 // protoc v4.25.1 -// source: chain_writer.proto +// source: contract_writer.proto package pb @@ -65,11 +65,11 @@ func (x TransactionStatus) String() string { } func (TransactionStatus) Descriptor() protoreflect.EnumDescriptor { - return file_chain_writer_proto_enumTypes[0].Descriptor() + return file_contract_writer_proto_enumTypes[0].Descriptor() } func (TransactionStatus) Type() protoreflect.EnumType { - return &file_chain_writer_proto_enumTypes[0] + return &file_contract_writer_proto_enumTypes[0] } func (x TransactionStatus) Number() protoreflect.EnumNumber { @@ -78,7 +78,7 @@ func (x TransactionStatus) Number() protoreflect.EnumNumber { // Deprecated: Use TransactionStatus.Descriptor instead. func (TransactionStatus) EnumDescriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{0} + return file_contract_writer_proto_rawDescGZIP(), []int{0} } type SubmitTransactionRequest struct { @@ -98,7 +98,7 @@ type SubmitTransactionRequest struct { func (x *SubmitTransactionRequest) Reset() { *x = SubmitTransactionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_chain_writer_proto_msgTypes[0] + mi := &file_contract_writer_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -111,7 +111,7 @@ func (x *SubmitTransactionRequest) String() string { func (*SubmitTransactionRequest) ProtoMessage() {} func (x *SubmitTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_chain_writer_proto_msgTypes[0] + mi := &file_contract_writer_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -124,7 +124,7 @@ func (x *SubmitTransactionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequest.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequest) Descriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{0} + return file_contract_writer_proto_rawDescGZIP(), []int{0} } func (x *SubmitTransactionRequest) GetContractName() string { @@ -188,7 +188,7 @@ type TransactionMeta struct { func (x *TransactionMeta) Reset() { *x = TransactionMeta{} if protoimpl.UnsafeEnabled { - mi := &file_chain_writer_proto_msgTypes[1] + mi := &file_contract_writer_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -201,7 +201,7 @@ func (x *TransactionMeta) String() string { func (*TransactionMeta) ProtoMessage() {} func (x *TransactionMeta) ProtoReflect() protoreflect.Message { - mi := &file_chain_writer_proto_msgTypes[1] + mi := &file_contract_writer_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -214,7 +214,7 @@ func (x *TransactionMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionMeta.ProtoReflect.Descriptor instead. func (*TransactionMeta) Descriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{1} + return file_contract_writer_proto_rawDescGZIP(), []int{1} } func (x *TransactionMeta) GetWorkflowExecutionId() string { @@ -231,7 +231,7 @@ func (x *TransactionMeta) GetGasLimit() *BigInt { return nil } -// GetTransactionStatusRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetTransactionStatus]. +// GetTransactionStatusRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetTransactionStatus]. type GetTransactionStatusRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -243,7 +243,7 @@ type GetTransactionStatusRequest struct { func (x *GetTransactionStatusRequest) Reset() { *x = GetTransactionStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_chain_writer_proto_msgTypes[2] + mi := &file_contract_writer_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -256,7 +256,7 @@ func (x *GetTransactionStatusRequest) String() string { func (*GetTransactionStatusRequest) ProtoMessage() {} func (x *GetTransactionStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_chain_writer_proto_msgTypes[2] + mi := &file_contract_writer_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -269,7 +269,7 @@ func (x *GetTransactionStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTransactionStatusRequest.ProtoReflect.Descriptor instead. func (*GetTransactionStatusRequest) Descriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{2} + return file_contract_writer_proto_rawDescGZIP(), []int{2} } func (x *GetTransactionStatusRequest) GetTransactionId() string { @@ -279,7 +279,7 @@ func (x *GetTransactionStatusRequest) GetTransactionId() string { return "" } -// GetTransactionStatusReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetTransactionStatus]. +// GetTransactionStatusReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetTransactionStatus]. type GetTransactionStatusReply struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -291,7 +291,7 @@ type GetTransactionStatusReply struct { func (x *GetTransactionStatusReply) Reset() { *x = GetTransactionStatusReply{} if protoimpl.UnsafeEnabled { - mi := &file_chain_writer_proto_msgTypes[3] + mi := &file_contract_writer_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -304,7 +304,7 @@ func (x *GetTransactionStatusReply) String() string { func (*GetTransactionStatusReply) ProtoMessage() {} func (x *GetTransactionStatusReply) ProtoReflect() protoreflect.Message { - mi := &file_chain_writer_proto_msgTypes[3] + mi := &file_contract_writer_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -317,7 +317,7 @@ func (x *GetTransactionStatusReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTransactionStatusReply.ProtoReflect.Descriptor instead. func (*GetTransactionStatusReply) Descriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{3} + return file_contract_writer_proto_rawDescGZIP(), []int{3} } func (x *GetTransactionStatusReply) GetTransactionStatus() TransactionStatus { @@ -327,7 +327,7 @@ func (x *GetTransactionStatusReply) GetTransactionStatus() TransactionStatus { return TransactionStatus_TRANSACTION_STATUS_UNKNOWN } -// GetFeeComponentsReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetFeeComponents]. +// GetFeeComponentsReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetFeeComponents]. type GetFeeComponentsReply struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -340,7 +340,7 @@ type GetFeeComponentsReply struct { func (x *GetFeeComponentsReply) Reset() { *x = GetFeeComponentsReply{} if protoimpl.UnsafeEnabled { - mi := &file_chain_writer_proto_msgTypes[4] + mi := &file_contract_writer_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -353,7 +353,7 @@ func (x *GetFeeComponentsReply) String() string { func (*GetFeeComponentsReply) ProtoMessage() {} func (x *GetFeeComponentsReply) ProtoReflect() protoreflect.Message { - mi := &file_chain_writer_proto_msgTypes[4] + mi := &file_contract_writer_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -366,7 +366,7 @@ func (x *GetFeeComponentsReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeeComponentsReply.ProtoReflect.Descriptor instead. func (*GetFeeComponentsReply) Descriptor() ([]byte, []int) { - return file_chain_writer_proto_rawDescGZIP(), []int{4} + return file_contract_writer_proto_rawDescGZIP(), []int{4} } func (x *GetFeeComponentsReply) GetExecutionFee() *BigInt { @@ -383,111 +383,111 @@ func (x *GetFeeComponentsReply) GetDataAvailabilityFee() *BigInt { return nil } -var File_chain_writer_proto protoreflect.FileDescriptor - -var file_chain_writer_proto_rawDesc = []byte{ - 0x0a, 0x12, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6c, 0x6f, 0x6f, 0x70, 0x1a, 0x0b, 0x63, 0x6f, 0x64, 0x65, - 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2c, 0x0a, - 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x79, - 0x74, 0x65, 0x73, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x29, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x22, 0x70, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x22, 0x44, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, +var File_contract_writer_proto protoreflect.FileDescriptor + +var file_contract_writer_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6c, 0x6f, 0x6f, 0x70, 0x1a, 0x0b, 0x63, + 0x6f, 0x64, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x2c, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x25, + 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, + 0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x70, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x45, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x09, 0x67, 0x61, + 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x08, 0x67, 0x61, 0x73, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x44, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x19, 0x47, + 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x8c, 0x01, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x0d, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x0c, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x65, 0x65, 0x12, 0x40, 0x0a, 0x15, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, - 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x13, 0x64, 0x61, 0x74, 0x61, 0x41, 0x76, 0x61, - 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x46, 0x65, 0x65, 0x2a, 0xd6, 0x01, 0x0a, - 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, - 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, - 0x52, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x49, 0x4e, - 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x52, 0x41, 0x4e, - 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x52, 0x41, 0x4e, 0x53, - 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, - 0x54, 0x41, 0x4c, 0x10, 0x05, 0x32, 0x85, 0x02, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, - 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x12, 0x49, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, - 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, - 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x8c, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x0d, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, + 0x0c, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x65, 0x65, 0x12, 0x40, 0x0a, + 0x15, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x13, 0x64, 0x61, 0x74, 0x61, + 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x46, 0x65, 0x65, 0x2a, + 0xd6, 0x01, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x43, 0x4f, + 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x52, 0x41, + 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x54, + 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x52, + 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x05, 0x32, 0x88, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x11, 0x53, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x14, 0x47, 0x65, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x46, + 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x46, + 0x65, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, + 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_chain_writer_proto_rawDescOnce sync.Once - file_chain_writer_proto_rawDescData = file_chain_writer_proto_rawDesc + file_contract_writer_proto_rawDescOnce sync.Once + file_contract_writer_proto_rawDescData = file_contract_writer_proto_rawDesc ) -func file_chain_writer_proto_rawDescGZIP() []byte { - file_chain_writer_proto_rawDescOnce.Do(func() { - file_chain_writer_proto_rawDescData = protoimpl.X.CompressGZIP(file_chain_writer_proto_rawDescData) +func file_contract_writer_proto_rawDescGZIP() []byte { + file_contract_writer_proto_rawDescOnce.Do(func() { + file_contract_writer_proto_rawDescData = protoimpl.X.CompressGZIP(file_contract_writer_proto_rawDescData) }) - return file_chain_writer_proto_rawDescData + return file_contract_writer_proto_rawDescData } -var file_chain_writer_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_chain_writer_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_chain_writer_proto_goTypes = []interface{}{ +var file_contract_writer_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_contract_writer_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_contract_writer_proto_goTypes = []interface{}{ (TransactionStatus)(0), // 0: loop.TransactionStatus (*SubmitTransactionRequest)(nil), // 1: loop.SubmitTransactionRequest (*TransactionMeta)(nil), // 2: loop.TransactionMeta @@ -498,7 +498,7 @@ var file_chain_writer_proto_goTypes = []interface{}{ (*BigInt)(nil), // 7: loop.BigInt (*emptypb.Empty)(nil), // 8: google.protobuf.Empty } -var file_chain_writer_proto_depIdxs = []int32{ +var file_contract_writer_proto_depIdxs = []int32{ 6, // 0: loop.SubmitTransactionRequest.params:type_name -> loop.VersionedBytes 2, // 1: loop.SubmitTransactionRequest.meta:type_name -> loop.TransactionMeta 7, // 2: loop.SubmitTransactionRequest.value:type_name -> loop.BigInt @@ -506,12 +506,12 @@ var file_chain_writer_proto_depIdxs = []int32{ 0, // 4: loop.GetTransactionStatusReply.transaction_status:type_name -> loop.TransactionStatus 7, // 5: loop.GetFeeComponentsReply.execution_fee:type_name -> loop.BigInt 7, // 6: loop.GetFeeComponentsReply.data_availability_fee:type_name -> loop.BigInt - 1, // 7: loop.ChainWriter.SubmitTransaction:input_type -> loop.SubmitTransactionRequest - 3, // 8: loop.ChainWriter.GetTransactionStatus:input_type -> loop.GetTransactionStatusRequest - 8, // 9: loop.ChainWriter.GetFeeComponents:input_type -> google.protobuf.Empty - 8, // 10: loop.ChainWriter.SubmitTransaction:output_type -> google.protobuf.Empty - 4, // 11: loop.ChainWriter.GetTransactionStatus:output_type -> loop.GetTransactionStatusReply - 5, // 12: loop.ChainWriter.GetFeeComponents:output_type -> loop.GetFeeComponentsReply + 1, // 7: loop.ContractWriter.SubmitTransaction:input_type -> loop.SubmitTransactionRequest + 3, // 8: loop.ContractWriter.GetTransactionStatus:input_type -> loop.GetTransactionStatusRequest + 8, // 9: loop.ContractWriter.GetFeeComponents:input_type -> google.protobuf.Empty + 8, // 10: loop.ContractWriter.SubmitTransaction:output_type -> google.protobuf.Empty + 4, // 11: loop.ContractWriter.GetTransactionStatus:output_type -> loop.GetTransactionStatusReply + 5, // 12: loop.ContractWriter.GetFeeComponents:output_type -> loop.GetFeeComponentsReply 10, // [10:13] is the sub-list for method output_type 7, // [7:10] is the sub-list for method input_type 7, // [7:7] is the sub-list for extension type_name @@ -519,15 +519,15 @@ var file_chain_writer_proto_depIdxs = []int32{ 0, // [0:7] is the sub-list for field type_name } -func init() { file_chain_writer_proto_init() } -func file_chain_writer_proto_init() { - if File_chain_writer_proto != nil { +func init() { file_contract_writer_proto_init() } +func file_contract_writer_proto_init() { + if File_contract_writer_proto != nil { return } file_codec_proto_init() file_relayer_proto_init() if !protoimpl.UnsafeEnabled { - file_chain_writer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_contract_writer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitTransactionRequest); i { case 0: return &v.state @@ -539,7 +539,7 @@ func file_chain_writer_proto_init() { return nil } } - file_chain_writer_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_contract_writer_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionMeta); i { case 0: return &v.state @@ -551,7 +551,7 @@ func file_chain_writer_proto_init() { return nil } } - file_chain_writer_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_contract_writer_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetTransactionStatusRequest); i { case 0: return &v.state @@ -563,7 +563,7 @@ func file_chain_writer_proto_init() { return nil } } - file_chain_writer_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_contract_writer_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetTransactionStatusReply); i { case 0: return &v.state @@ -575,7 +575,7 @@ func file_chain_writer_proto_init() { return nil } } - file_chain_writer_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_contract_writer_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetFeeComponentsReply); i { case 0: return &v.state @@ -592,19 +592,19 @@ func file_chain_writer_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_chain_writer_proto_rawDesc, + RawDescriptor: file_contract_writer_proto_rawDesc, NumEnums: 1, NumMessages: 5, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_chain_writer_proto_goTypes, - DependencyIndexes: file_chain_writer_proto_depIdxs, - EnumInfos: file_chain_writer_proto_enumTypes, - MessageInfos: file_chain_writer_proto_msgTypes, + GoTypes: file_contract_writer_proto_goTypes, + DependencyIndexes: file_contract_writer_proto_depIdxs, + EnumInfos: file_contract_writer_proto_enumTypes, + MessageInfos: file_contract_writer_proto_msgTypes, }.Build() - File_chain_writer_proto = out.File - file_chain_writer_proto_rawDesc = nil - file_chain_writer_proto_goTypes = nil - file_chain_writer_proto_depIdxs = nil + File_contract_writer_proto = out.File + file_contract_writer_proto_rawDesc = nil + file_contract_writer_proto_goTypes = nil + file_contract_writer_proto_depIdxs = nil } diff --git a/pkg/loop/internal/pb/chain_writer.proto b/pkg/loop/internal/pb/contract_writer.proto similarity index 86% rename from pkg/loop/internal/pb/chain_writer.proto rename to pkg/loop/internal/pb/contract_writer.proto index db03e2a7c..dd33f99cd 100644 --- a/pkg/loop/internal/pb/chain_writer.proto +++ b/pkg/loop/internal/pb/contract_writer.proto @@ -8,7 +8,7 @@ import "codec.proto"; import "relayer.proto"; import "google/protobuf/empty.proto"; -service ChainWriter { +service ContractWriter { rpc SubmitTransaction(SubmitTransactionRequest) returns (google.protobuf.Empty) {} rpc GetTransactionStatus(GetTransactionStatusRequest) returns (GetTransactionStatusReply) {} rpc GetFeeComponents(google.protobuf.Empty) returns (GetFeeComponentsReply) {} @@ -29,7 +29,7 @@ message TransactionMeta { BigInt gas_limit = 2; } -// GetTransactionStatusRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetTransactionStatus]. +// GetTransactionStatusRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetTransactionStatus]. message GetTransactionStatusRequest { string transaction_id = 1; } @@ -45,12 +45,12 @@ enum TransactionStatus { TRANSACTION_STATUS_FATAL = 5; } -// GetTransactionStatusReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetTransactionStatus]. +// GetTransactionStatusReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetTransactionStatus]. message GetTransactionStatusReply { TransactionStatus transaction_status = 1; } -// GetFeeComponentsReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainWriter.GetFeeComponents]. +// GetFeeComponentsReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ContractWriter.GetFeeComponents]. message GetFeeComponentsReply { BigInt execution_fee = 1; BigInt data_availability_fee = 2; diff --git a/pkg/loop/internal/pb/contract_writer_grpc.pb.go b/pkg/loop/internal/pb/contract_writer_grpc.pb.go new file mode 100644 index 000000000..4f45583fd --- /dev/null +++ b/pkg/loop/internal/pb/contract_writer_grpc.pb.go @@ -0,0 +1,184 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.25.1 +// source: contract_writer.proto + +package pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + ContractWriter_SubmitTransaction_FullMethodName = "/loop.ContractWriter/SubmitTransaction" + ContractWriter_GetTransactionStatus_FullMethodName = "/loop.ContractWriter/GetTransactionStatus" + ContractWriter_GetFeeComponents_FullMethodName = "/loop.ContractWriter/GetFeeComponents" +) + +// ContractWriterClient is the client API for ContractWriter service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ContractWriterClient interface { + SubmitTransaction(ctx context.Context, in *SubmitTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + GetTransactionStatus(ctx context.Context, in *GetTransactionStatusRequest, opts ...grpc.CallOption) (*GetTransactionStatusReply, error) + GetFeeComponents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetFeeComponentsReply, error) +} + +type contractWriterClient struct { + cc grpc.ClientConnInterface +} + +func NewContractWriterClient(cc grpc.ClientConnInterface) ContractWriterClient { + return &contractWriterClient{cc} +} + +func (c *contractWriterClient) SubmitTransaction(ctx context.Context, in *SubmitTransactionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, ContractWriter_SubmitTransaction_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *contractWriterClient) GetTransactionStatus(ctx context.Context, in *GetTransactionStatusRequest, opts ...grpc.CallOption) (*GetTransactionStatusReply, error) { + out := new(GetTransactionStatusReply) + err := c.cc.Invoke(ctx, ContractWriter_GetTransactionStatus_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *contractWriterClient) GetFeeComponents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetFeeComponentsReply, error) { + out := new(GetFeeComponentsReply) + err := c.cc.Invoke(ctx, ContractWriter_GetFeeComponents_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ContractWriterServer is the server API for ContractWriter service. +// All implementations must embed UnimplementedContractWriterServer +// for forward compatibility +type ContractWriterServer interface { + SubmitTransaction(context.Context, *SubmitTransactionRequest) (*emptypb.Empty, error) + GetTransactionStatus(context.Context, *GetTransactionStatusRequest) (*GetTransactionStatusReply, error) + GetFeeComponents(context.Context, *emptypb.Empty) (*GetFeeComponentsReply, error) + mustEmbedUnimplementedContractWriterServer() +} + +// UnimplementedContractWriterServer must be embedded to have forward compatible implementations. +type UnimplementedContractWriterServer struct { +} + +func (UnimplementedContractWriterServer) SubmitTransaction(context.Context, *SubmitTransactionRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitTransaction not implemented") +} +func (UnimplementedContractWriterServer) GetTransactionStatus(context.Context, *GetTransactionStatusRequest) (*GetTransactionStatusReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTransactionStatus not implemented") +} +func (UnimplementedContractWriterServer) GetFeeComponents(context.Context, *emptypb.Empty) (*GetFeeComponentsReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFeeComponents not implemented") +} +func (UnimplementedContractWriterServer) mustEmbedUnimplementedContractWriterServer() {} + +// UnsafeContractWriterServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ContractWriterServer will +// result in compilation errors. +type UnsafeContractWriterServer interface { + mustEmbedUnimplementedContractWriterServer() +} + +func RegisterContractWriterServer(s grpc.ServiceRegistrar, srv ContractWriterServer) { + s.RegisterService(&ContractWriter_ServiceDesc, srv) +} + +func _ContractWriter_SubmitTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitTransactionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ContractWriterServer).SubmitTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ContractWriter_SubmitTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ContractWriterServer).SubmitTransaction(ctx, req.(*SubmitTransactionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ContractWriter_GetTransactionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTransactionStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ContractWriterServer).GetTransactionStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ContractWriter_GetTransactionStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ContractWriterServer).GetTransactionStatus(ctx, req.(*GetTransactionStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ContractWriter_GetFeeComponents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ContractWriterServer).GetFeeComponents(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ContractWriter_GetFeeComponents_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ContractWriterServer).GetFeeComponents(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +// ContractWriter_ServiceDesc is the grpc.ServiceDesc for ContractWriter service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ContractWriter_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "loop.ContractWriter", + HandlerType: (*ContractWriterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SubmitTransaction", + Handler: _ContractWriter_SubmitTransaction_Handler, + }, + { + MethodName: "GetTransactionStatus", + Handler: _ContractWriter_GetTransactionStatus_Handler, + }, + { + MethodName: "GetFeeComponents", + Handler: _ContractWriter_GetFeeComponents_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "contract_writer.proto", +} diff --git a/pkg/loop/internal/pb/generate.go b/pkg/loop/internal/pb/generate.go index 05dbfbde4..1c3067891 100644 --- a/pkg/loop/internal/pb/generate.go +++ b/pkg/loop/internal/pb/generate.go @@ -5,7 +5,7 @@ //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative telemetry.proto //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative pipeline_runner.proto //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative contract_reader.proto -//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative chain_writer.proto +//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative contract_writer.proto //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative median_datasource.proto //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative codec.proto //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative keyvalue_store.proto diff --git a/pkg/loop/internal/pb/relayer.pb.go b/pkg/loop/internal/pb/relayer.pb.go index 6e947679c..8eb519064 100644 --- a/pkg/loop/internal/pb/relayer.pb.go +++ b/pkg/loop/internal/pb/relayer.pb.go @@ -424,17 +424,17 @@ func (x *PluginArgs) GetPluginConfig() []byte { return nil } -// NewChainWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewChainWriter]. -type NewChainWriterRequest struct { +// NewContractWriterRequest has request parameters for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. +type NewContractWriterRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChainWriterConfig []byte `protobuf:"bytes,1,opt,name=chainWriterConfig,proto3" json:"chainWriterConfig,omitempty"` + ContractWriterConfig []byte `protobuf:"bytes,1,opt,name=contractWriterConfig,proto3" json:"contractWriterConfig,omitempty"` } -func (x *NewChainWriterRequest) Reset() { - *x = NewChainWriterRequest{} +func (x *NewContractWriterRequest) Reset() { + *x = NewContractWriterRequest{} if protoimpl.UnsafeEnabled { mi := &file_relayer_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -442,13 +442,13 @@ func (x *NewChainWriterRequest) Reset() { } } -func (x *NewChainWriterRequest) String() string { +func (x *NewContractWriterRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NewChainWriterRequest) ProtoMessage() {} +func (*NewContractWriterRequest) ProtoMessage() {} -func (x *NewChainWriterRequest) ProtoReflect() protoreflect.Message { +func (x *NewContractWriterRequest) ProtoReflect() protoreflect.Message { mi := &file_relayer_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -460,29 +460,29 @@ func (x *NewChainWriterRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NewChainWriterRequest.ProtoReflect.Descriptor instead. -func (*NewChainWriterRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use NewContractWriterRequest.ProtoReflect.Descriptor instead. +func (*NewContractWriterRequest) Descriptor() ([]byte, []int) { return file_relayer_proto_rawDescGZIP(), []int{7} } -func (x *NewChainWriterRequest) GetChainWriterConfig() []byte { +func (x *NewContractWriterRequest) GetContractWriterConfig() []byte { if x != nil { - return x.ChainWriterConfig + return x.ContractWriterConfig } return nil } -// NewChainWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewChainWriter]. -type NewChainWriterReply struct { +// NewContractWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. +type NewContractWriterReply struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChainWriterID uint32 `protobuf:"varint,1,opt,name=chainWriterID,proto3" json:"chainWriterID,omitempty"` + ContractWriterID uint32 `protobuf:"varint,1,opt,name=contractWriterID,proto3" json:"contractWriterID,omitempty"` } -func (x *NewChainWriterReply) Reset() { - *x = NewChainWriterReply{} +func (x *NewContractWriterReply) Reset() { + *x = NewContractWriterReply{} if protoimpl.UnsafeEnabled { mi := &file_relayer_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -490,13 +490,13 @@ func (x *NewChainWriterReply) Reset() { } } -func (x *NewChainWriterReply) String() string { +func (x *NewContractWriterReply) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NewChainWriterReply) ProtoMessage() {} +func (*NewContractWriterReply) ProtoMessage() {} -func (x *NewChainWriterReply) ProtoReflect() protoreflect.Message { +func (x *NewContractWriterReply) ProtoReflect() protoreflect.Message { mi := &file_relayer_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -508,14 +508,14 @@ func (x *NewChainWriterReply) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NewChainWriterReply.ProtoReflect.Descriptor instead. -func (*NewChainWriterReply) Descriptor() ([]byte, []int) { +// Deprecated: Use NewContractWriterReply.ProtoReflect.Descriptor instead. +func (*NewContractWriterReply) Descriptor() ([]byte, []int) { return file_relayer_proto_rawDescGZIP(), []int{8} } -func (x *NewChainWriterReply) GetChainWriterID() uint32 { +func (x *NewContractWriterReply) GetContractWriterID() uint32 { if x != nil { - return x.ChainWriterID + return x.ContractWriterID } return 0 } @@ -2635,332 +2635,334 @@ var file_relayer_proto_rawDesc = []byte{ 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x45, 0x0a, 0x15, - 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, - 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x22, 0x3b, 0x0a, 0x13, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, - 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x44, - 0x22, 0x4e, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x7b, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, - 0x73, 0x12, 0x30, 0x0a, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x41, 0x72, 0x67, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x50, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x41, 0x72, 0x67, 0x73, 0x52, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x41, - 0x72, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, - 0x10, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x49, 0x0a, 0x18, 0x4e, 0x65, 0x77, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, - 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x52, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, - 0x41, 0x72, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, - 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x13, 0x0a, 0x11, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x31, 0x0a, 0x0f, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x68, 0x65, - 0x61, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x47, - 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x4f, 0x0a, 0x0b, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x55, 0x0a, 0x17, - 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, - 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x7d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x05, - 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x6e, - 0x6f, 0x64, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, - 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0x68, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x82, 0x01, 0x0a, - 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x24, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, - 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, - 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x22, 0xa6, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x69, - 0x67, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, - 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x0a, 0x01, 0x46, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x01, 0x46, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6f, - 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x15, - 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6f, 0x66, 0x66, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x66, 0x66, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x53, 0x0a, 0x13, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, - 0x37, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6f, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x4e, 0x0a, 0x18, + 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x44, 0x0a, 0x16, + 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, + 0x49, 0x44, 0x22, 0x4e, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, + 0x0a, 0x14, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x10, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x7b, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x41, + 0x72, 0x67, 0x73, 0x12, 0x30, 0x0a, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x41, 0x72, 0x67, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x41, 0x72, 0x67, 0x73, 0x52, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x41, 0x72, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x2a, 0x0a, 0x10, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x49, 0x0a, 0x18, 0x4e, + 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x41, 0x72, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x72, 0x65, 0x6c, + 0x61, 0x79, 0x41, 0x72, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x44, 0x22, 0x13, 0x0a, 0x11, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x31, 0x0a, 0x0f, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, + 0x68, 0x65, 0x61, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, + 0x13, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x4f, 0x0a, + 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x55, + 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x7d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, + 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0f, + 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x68, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x82, + 0x01, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x24, 0x0a, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x22, 0x0a, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x22, 0xa6, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, + 0x69, 0x74, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x0a, 0x01, 0x46, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x01, 0x46, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x6e, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0d, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, + 0x0a, 0x15, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6f, + 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x66, + 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x53, 0x0a, 0x13, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x22, 0x37, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x22, 0x1c, 0x0a, 0x1a, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, - 0x0a, 0x18, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3d, 0x0a, 0x13, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, - 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x51, 0x0a, 0x11, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3c, 0x0a, 0x0e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1a, 0x0a, 0x18, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x0a, 0x16, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, - 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x22, 0x61, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x14, 0x0a, - 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 0x22, 0x6e, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x48, - 0x61, 0x73, 0x68, 0x22, 0x52, 0x0a, 0x1a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0xc8, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x0d, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x62, - 0x0a, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x23, 0x0a, 0x21, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, 0x64, 0x45, 0x70, 0x6f, 0x63, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5b, 0x0a, 0x1f, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, - 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x14, 0x0a, 0x12, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2c, 0x0a, 0x10, 0x46, - 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1f, 0x0a, 0x09, 0x4e, 0x61, 0x6d, - 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x11, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x4d, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, - 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x1a, - 0x3f, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x3a, 0x0a, 0x06, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4b, 0x0a, 0x11, - 0x53, 0x74, 0x61, 0x72, 0x6b, 0x6e, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x1a, 0x0a, 0x01, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x01, 0x78, 0x12, 0x1a, 0x0a, - 0x01, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x01, 0x79, 0x22, 0x37, 0x0a, 0x13, 0x53, 0x74, 0x61, - 0x72, 0x6b, 0x6e, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x20, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x32, 0x4f, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x6c, 0x61, - 0x79, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, - 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x61, - 0x79, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x32, 0x73, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, - 0x39, 0x0a, 0x08, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, 0x53, 0x69, - 0x67, 0x6e, 0x12, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x69, 0x67, - 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xf2, 0x04, 0x0a, 0x07, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, - 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x22, 0x1c, 0x0a, 0x1a, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x66, 0x0a, 0x18, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x0e, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3d, 0x0a, 0x13, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x26, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x49, 0x6e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x49, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x51, 0x0a, 0x11, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3c, 0x0a, 0x0e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1a, 0x0a, 0x18, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x0a, 0x16, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x22, 0x61, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, + 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x6e, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72, + 0x61, 0x48, 0x61, 0x73, 0x68, 0x22, 0x52, 0x0a, 0x1a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0xc8, 0x01, 0x0a, 0x0f, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, + 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x12, 0x62, 0x0a, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x6e, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x23, 0x0a, 0x21, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, 0x64, 0x45, 0x70, + 0x6f, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5b, 0x0a, 0x1f, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x41, 0x6e, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x14, 0x0a, 0x12, 0x46, 0x72, 0x6f, 0x6d, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2c, 0x0a, + 0x10, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1f, 0x0a, 0x09, 0x4e, + 0x61, 0x6d, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xa3, 0x01, 0x0a, + 0x11, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x4d, 0x0a, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x1a, 0x3f, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x3a, 0x0a, 0x06, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4b, + 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x6b, 0x6e, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x01, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x01, 0x78, 0x12, + 0x1a, 0x0a, 0x01, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x01, 0x79, 0x22, 0x37, 0x0a, 0x13, 0x53, + 0x74, 0x61, 0x72, 0x6b, 0x6e, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x20, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x52, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x32, 0x4f, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0x73, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x12, 0x39, 0x0a, 0x08, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x04, + 0x53, 0x69, 0x67, 0x6e, 0x12, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, 0x69, 0x67, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x53, + 0x69, 0x67, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xfb, 0x04, 0x0a, 0x07, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, + 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, + 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x11, 0x4e, + 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x11, 0x4e, 0x65, - 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, - 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, - 0x3e, 0x0a, 0x0a, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x17, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, - 0x4a, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x10, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, - 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, - 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0xb6, 0x01, - 0x0a, 0x16, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x56, - 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0x8d, 0x02, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, - 0x12, 0x59, 0x0a, 0x13, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, + 0x70, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0a, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0xb6, 0x01, 0x0a, 0x16, 0x4f, 0x66, 0x66, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x12, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, + 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x32, 0x8d, 0x02, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x13, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x4c, - 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x00, 0x12, 0x53, 0x0a, 0x11, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0x82, 0x02, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x38, - 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x6e, 0x0a, 0x1a, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, - 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x41, 0x6e, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, + 0x6c, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x11, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x32, 0x82, 0x02, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x08, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x6e, 0x0a, 0x1a, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, 0x64, 0x45, 0x70, 0x6f, 0x63, - 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0b, 0x46, 0x72, 0x6f, 0x6d, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x46, - 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xf5, 0x01, 0x0a, 0x07, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, - 0x61, 0x6d, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x05, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x16, + 0x68, 0x12, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, 0x64, 0x45, 0x70, + 0x6f, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x41, 0x6e, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0b, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x32, 0xf5, 0x01, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, - 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, - 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x39, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0c, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x43, + 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, + 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2984,8 +2986,8 @@ var file_relayer_proto_goTypes = []interface{}{ (*SignReply)(nil), // 4: loop.SignReply (*RelayArgs)(nil), // 5: loop.RelayArgs (*PluginArgs)(nil), // 6: loop.PluginArgs - (*NewChainWriterRequest)(nil), // 7: loop.NewChainWriterRequest - (*NewChainWriterReply)(nil), // 8: loop.NewChainWriterReply + (*NewContractWriterRequest)(nil), // 7: loop.NewContractWriterRequest + (*NewContractWriterReply)(nil), // 8: loop.NewContractWriterReply (*NewContractReaderRequest)(nil), // 9: loop.NewContractReaderRequest (*NewContractReaderReply)(nil), // 10: loop.NewContractReaderReply (*NewPluginProviderRequest)(nil), // 11: loop.NewPluginProviderRequest @@ -3050,7 +3052,7 @@ var file_relayer_proto_depIdxs = []int32{ 0, // 16: loop.PluginRelayer.NewRelayer:input_type -> loop.NewRelayerRequest 51, // 17: loop.Keystore.Accounts:input_type -> google.protobuf.Empty 3, // 18: loop.Keystore.Sign:input_type -> loop.SignRequest - 7, // 19: loop.Relayer.NewChainWriter:input_type -> loop.NewChainWriterRequest + 7, // 19: loop.Relayer.NewContractWriter:input_type -> loop.NewContractWriterRequest 9, // 20: loop.Relayer.NewContractReader:input_type -> loop.NewContractReaderRequest 13, // 21: loop.Relayer.NewConfigProvider:input_type -> loop.NewConfigProviderRequest 11, // 22: loop.Relayer.NewPluginProvider:input_type -> loop.NewPluginProviderRequest @@ -3073,7 +3075,7 @@ var file_relayer_proto_depIdxs = []int32{ 1, // 39: loop.PluginRelayer.NewRelayer:output_type -> loop.NewRelayerReply 2, // 40: loop.Keystore.Accounts:output_type -> loop.AccountsReply 4, // 41: loop.Keystore.Sign:output_type -> loop.SignReply - 8, // 42: loop.Relayer.NewChainWriter:output_type -> loop.NewChainWriterReply + 8, // 42: loop.Relayer.NewContractWriter:output_type -> loop.NewContractWriterReply 10, // 43: loop.Relayer.NewContractReader:output_type -> loop.NewContractReaderReply 14, // 44: loop.Relayer.NewConfigProvider:output_type -> loop.NewConfigProviderReply 12, // 45: loop.Relayer.NewPluginProvider:output_type -> loop.NewPluginProviderReply @@ -3192,7 +3194,7 @@ func file_relayer_proto_init() { } } file_relayer_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewChainWriterRequest); i { + switch v := v.(*NewContractWriterRequest); i { case 0: return &v.state case 1: @@ -3204,7 +3206,7 @@ func file_relayer_proto_init() { } } file_relayer_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewChainWriterReply); i { + switch v := v.(*NewContractWriterReply); i { case 0: return &v.state case 1: diff --git a/pkg/loop/internal/pb/relayer.proto b/pkg/loop/internal/pb/relayer.proto index efbeda99e..211351d2c 100644 --- a/pkg/loop/internal/pb/relayer.proto +++ b/pkg/loop/internal/pb/relayer.proto @@ -42,7 +42,7 @@ message SignReply { } service Relayer { - rpc NewChainWriter(NewChainWriterRequest) returns (NewChainWriterReply) {} + rpc NewContractWriter(NewContractWriterRequest) returns (NewContractWriterReply) {} rpc NewContractReader (NewContractReaderRequest) returns (NewContractReaderReply) {} rpc NewConfigProvider (NewConfigProviderRequest) returns (NewConfigProviderReply) {} rpc NewPluginProvider (NewPluginProviderRequest) returns (NewPluginProviderReply) {} @@ -69,14 +69,14 @@ message PluginArgs { bytes pluginConfig = 2; } -// NewChainWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewChainWriter]. -message NewChainWriterRequest { - bytes chainWriterConfig = 1; +// NewContractWriterRequest has request parameters for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. +message NewContractWriterRequest { + bytes contractWriterConfig = 1; } -// NewChainWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewChainWriter]. -message NewChainWriterReply { - uint32 chainWriterID = 1; +// NewContractWriterReply has return arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractWriter]. +message NewContractWriterReply { + uint32 contractWriterID = 1; } // NewContractReaderRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/loop.Relayer.NewContractReader]. diff --git a/pkg/loop/internal/pb/relayer_grpc.pb.go b/pkg/loop/internal/pb/relayer_grpc.pb.go index 214842b92..aa6a804db 100644 --- a/pkg/loop/internal/pb/relayer_grpc.pb.go +++ b/pkg/loop/internal/pb/relayer_grpc.pb.go @@ -237,7 +237,7 @@ var Keystore_ServiceDesc = grpc.ServiceDesc{ } const ( - Relayer_NewChainWriter_FullMethodName = "/loop.Relayer/NewChainWriter" + Relayer_NewContractWriter_FullMethodName = "/loop.Relayer/NewContractWriter" Relayer_NewContractReader_FullMethodName = "/loop.Relayer/NewContractReader" Relayer_NewConfigProvider_FullMethodName = "/loop.Relayer/NewConfigProvider" Relayer_NewPluginProvider_FullMethodName = "/loop.Relayer/NewPluginProvider" @@ -251,7 +251,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type RelayerClient interface { - NewChainWriter(ctx context.Context, in *NewChainWriterRequest, opts ...grpc.CallOption) (*NewChainWriterReply, error) + NewContractWriter(ctx context.Context, in *NewContractWriterRequest, opts ...grpc.CallOption) (*NewContractWriterReply, error) NewContractReader(ctx context.Context, in *NewContractReaderRequest, opts ...grpc.CallOption) (*NewContractReaderReply, error) NewConfigProvider(ctx context.Context, in *NewConfigProviderRequest, opts ...grpc.CallOption) (*NewConfigProviderReply, error) NewPluginProvider(ctx context.Context, in *NewPluginProviderRequest, opts ...grpc.CallOption) (*NewPluginProviderReply, error) @@ -269,9 +269,9 @@ func NewRelayerClient(cc grpc.ClientConnInterface) RelayerClient { return &relayerClient{cc} } -func (c *relayerClient) NewChainWriter(ctx context.Context, in *NewChainWriterRequest, opts ...grpc.CallOption) (*NewChainWriterReply, error) { - out := new(NewChainWriterReply) - err := c.cc.Invoke(ctx, Relayer_NewChainWriter_FullMethodName, in, out, opts...) +func (c *relayerClient) NewContractWriter(ctx context.Context, in *NewContractWriterRequest, opts ...grpc.CallOption) (*NewContractWriterReply, error) { + out := new(NewContractWriterReply) + err := c.cc.Invoke(ctx, Relayer_NewContractWriter_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -345,7 +345,7 @@ func (c *relayerClient) Transact(ctx context.Context, in *TransactionRequest, op // All implementations must embed UnimplementedRelayerServer // for forward compatibility type RelayerServer interface { - NewChainWriter(context.Context, *NewChainWriterRequest) (*NewChainWriterReply, error) + NewContractWriter(context.Context, *NewContractWriterRequest) (*NewContractWriterReply, error) NewContractReader(context.Context, *NewContractReaderRequest) (*NewContractReaderReply, error) NewConfigProvider(context.Context, *NewConfigProviderRequest) (*NewConfigProviderReply, error) NewPluginProvider(context.Context, *NewPluginProviderRequest) (*NewPluginProviderReply, error) @@ -360,8 +360,8 @@ type RelayerServer interface { type UnimplementedRelayerServer struct { } -func (UnimplementedRelayerServer) NewChainWriter(context.Context, *NewChainWriterRequest) (*NewChainWriterReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method NewChainWriter not implemented") +func (UnimplementedRelayerServer) NewContractWriter(context.Context, *NewContractWriterRequest) (*NewContractWriterReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method NewContractWriter not implemented") } func (UnimplementedRelayerServer) NewContractReader(context.Context, *NewContractReaderRequest) (*NewContractReaderReply, error) { return nil, status.Errorf(codes.Unimplemented, "method NewContractReader not implemented") @@ -397,20 +397,20 @@ func RegisterRelayerServer(s grpc.ServiceRegistrar, srv RelayerServer) { s.RegisterService(&Relayer_ServiceDesc, srv) } -func _Relayer_NewChainWriter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NewChainWriterRequest) +func _Relayer_NewContractWriter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NewContractWriterRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(RelayerServer).NewChainWriter(ctx, in) + return srv.(RelayerServer).NewContractWriter(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Relayer_NewChainWriter_FullMethodName, + FullMethod: Relayer_NewContractWriter_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RelayerServer).NewChainWriter(ctx, req.(*NewChainWriterRequest)) + return srv.(RelayerServer).NewContractWriter(ctx, req.(*NewContractWriterRequest)) } return interceptor(ctx, in, info, handler) } @@ -549,8 +549,8 @@ var Relayer_ServiceDesc = grpc.ServiceDesc{ HandlerType: (*RelayerServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "NewChainWriter", - Handler: _Relayer_NewChainWriter_Handler, + MethodName: "NewContractWriter", + Handler: _Relayer_NewContractWriter_Handler, }, { MethodName: "NewContractReader", diff --git a/pkg/loop/internal/pb/relayerset/relayerset.pb.go b/pkg/loop/internal/pb/relayerset/relayerset.pb.go index 05e07cabf..da4346d0b 100644 --- a/pkg/loop/internal/pb/relayerset/relayerset.pb.go +++ b/pkg/loop/internal/pb/relayerset/relayerset.pb.go @@ -675,17 +675,17 @@ func (x *NewContractReaderResponse) GetContractReaderId() uint32 { return 0 } -type NewChainWriterRequest struct { +type NewContractWriterRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RelayerId *RelayerId `protobuf:"bytes,1,opt,name=relayerId,proto3" json:"relayerId,omitempty"` - ChainWriterConfig []byte `protobuf:"bytes,2,opt,name=chainWriterConfig,proto3" json:"chainWriterConfig,omitempty"` + RelayerId *RelayerId `protobuf:"bytes,1,opt,name=relayerId,proto3" json:"relayerId,omitempty"` + ContractWriterConfig []byte `protobuf:"bytes,2,opt,name=contractWriterConfig,proto3" json:"contractWriterConfig,omitempty"` } -func (x *NewChainWriterRequest) Reset() { - *x = NewChainWriterRequest{} +func (x *NewContractWriterRequest) Reset() { + *x = NewContractWriterRequest{} if protoimpl.UnsafeEnabled { mi := &file_relayerset_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -693,13 +693,13 @@ func (x *NewChainWriterRequest) Reset() { } } -func (x *NewChainWriterRequest) String() string { +func (x *NewContractWriterRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NewChainWriterRequest) ProtoMessage() {} +func (*NewContractWriterRequest) ProtoMessage() {} -func (x *NewChainWriterRequest) ProtoReflect() protoreflect.Message { +func (x *NewContractWriterRequest) ProtoReflect() protoreflect.Message { mi := &file_relayerset_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -711,35 +711,35 @@ func (x *NewChainWriterRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NewChainWriterRequest.ProtoReflect.Descriptor instead. -func (*NewChainWriterRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use NewContractWriterRequest.ProtoReflect.Descriptor instead. +func (*NewContractWriterRequest) Descriptor() ([]byte, []int) { return file_relayerset_proto_rawDescGZIP(), []int{12} } -func (x *NewChainWriterRequest) GetRelayerId() *RelayerId { +func (x *NewContractWriterRequest) GetRelayerId() *RelayerId { if x != nil { return x.RelayerId } return nil } -func (x *NewChainWriterRequest) GetChainWriterConfig() []byte { +func (x *NewContractWriterRequest) GetContractWriterConfig() []byte { if x != nil { - return x.ChainWriterConfig + return x.ContractWriterConfig } return nil } -type NewChainWriterResponse struct { +type NewContractWriterResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChainWriterId uint32 `protobuf:"varint,1,opt,name=chainWriterId,proto3" json:"chainWriterId,omitempty"` + ContractWriterId uint32 `protobuf:"varint,1,opt,name=contractWriterId,proto3" json:"contractWriterId,omitempty"` } -func (x *NewChainWriterResponse) Reset() { - *x = NewChainWriterResponse{} +func (x *NewContractWriterResponse) Reset() { + *x = NewContractWriterResponse{} if protoimpl.UnsafeEnabled { mi := &file_relayerset_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -747,13 +747,13 @@ func (x *NewChainWriterResponse) Reset() { } } -func (x *NewChainWriterResponse) String() string { +func (x *NewContractWriterResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NewChainWriterResponse) ProtoMessage() {} +func (*NewContractWriterResponse) ProtoMessage() {} -func (x *NewChainWriterResponse) ProtoReflect() protoreflect.Message { +func (x *NewContractWriterResponse) ProtoReflect() protoreflect.Message { mi := &file_relayerset_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -765,14 +765,14 @@ func (x *NewChainWriterResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NewChainWriterResponse.ProtoReflect.Descriptor instead. -func (*NewChainWriterResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use NewContractWriterResponse.ProtoReflect.Descriptor instead. +func (*NewContractWriterResponse) Descriptor() ([]byte, []int) { return file_relayerset_proto_rawDescGZIP(), []int{13} } -func (x *NewChainWriterResponse) GetChainWriterId() uint32 { +func (x *NewContractWriterResponse) GetContractWriterId() uint32 { if x != nil { - return x.ChainWriterId + return x.ContractWriterId } return 0 } @@ -1066,111 +1066,113 @@ var file_relayerset_proto_rawDesc = []byte{ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x7f, 0x0a, 0x15, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, - 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x09, + 0x72, 0x49, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x52, + 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x47, + 0x0a, 0x19, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x4d, 0x0a, 0x11, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x52, 0x09, 0x72, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, - 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x11, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x22, 0x3e, 0x0a, 0x16, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, - 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, - 0x65, 0x72, 0x49, 0x64, 0x22, 0x4d, 0x0a, 0x11, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, - 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x52, 0x09, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x5e, 0x0a, 0x12, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x22, 0xaa, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x39, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x29, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xe4, 0x07, 0x0a, 0x0a, - 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x65, 0x74, 0x12, 0x50, 0x0a, 0x03, 0x47, 0x65, - 0x74, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x04, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, - 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, - 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x11, 0x4e, 0x65, 0x77, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x29, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, - 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x50, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x29, 0x2e, 0x6c, + 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x5e, 0x0a, 0x12, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xaa, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x39, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xed, + 0x07, 0x0a, 0x0a, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x53, 0x65, 0x74, 0x12, 0x50, 0x0a, + 0x03, 0x47, 0x65, 0x74, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x5b, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, + 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, + 0x6c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, + 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x11, + 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, - 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, - 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, - 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, - 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, - 0x12, 0x44, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, - 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, - 0x72, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, + 0x65, 0x77, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x11, 0x4e, 0x65, + 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, + 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x11, 0x4e, 0x65, 0x77, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x12, 0x29, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, + 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x61, 0x0a, 0x13, - 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, - 0x2c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, - 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x51, 0x0a, 0x0b, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, - 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x65, 0x61, + 0x64, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x61, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, + 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x2c, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0b, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, + 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, + 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x2e, 0x4c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, - 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x62, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, - 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x4e, + 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, + 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x70, 0x62, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x65, 0x74, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1199,8 +1201,8 @@ var file_relayerset_proto_goTypes = []interface{}{ (*NewPluginProviderResponse)(nil), // 9: loop.relayerset.NewPluginProviderResponse (*NewContractReaderRequest)(nil), // 10: loop.relayerset.NewContractReaderRequest (*NewContractReaderResponse)(nil), // 11: loop.relayerset.NewContractReaderResponse - (*NewChainWriterRequest)(nil), // 12: loop.relayerset.NewChainWriterRequest - (*NewChainWriterResponse)(nil), // 13: loop.relayerset.NewChainWriterResponse + (*NewContractWriterRequest)(nil), // 12: loop.relayerset.NewContractWriterRequest + (*NewContractWriterResponse)(nil), // 13: loop.relayerset.NewContractWriterResponse (*LatestHeadRequest)(nil), // 14: loop.relayerset.LatestHeadRequest (*LatestHeadResponse)(nil), // 15: loop.relayerset.LatestHeadResponse (*RelayerHealthReportResponse)(nil), // 16: loop.relayerset.RelayerHealthReportResponse @@ -1218,14 +1220,14 @@ var file_relayerset_proto_depIdxs = []int32{ 5, // 6: loop.relayerset.NewPluginProviderRequest.relayArgs:type_name -> loop.relayerset.RelayArgs 7, // 7: loop.relayerset.NewPluginProviderRequest.pluginArgs:type_name -> loop.relayerset.PluginArgs 0, // 8: loop.relayerset.NewContractReaderRequest.relayerId:type_name -> loop.relayerset.RelayerId - 0, // 9: loop.relayerset.NewChainWriterRequest.relayerId:type_name -> loop.relayerset.RelayerId + 0, // 9: loop.relayerset.NewContractWriterRequest.relayerId:type_name -> loop.relayerset.RelayerId 0, // 10: loop.relayerset.LatestHeadRequest.relayerId:type_name -> loop.relayerset.RelayerId 18, // 11: loop.relayerset.RelayerHealthReportResponse.report:type_name -> loop.relayerset.RelayerHealthReportResponse.ReportEntry 1, // 12: loop.relayerset.RelayerSet.Get:input_type -> loop.relayerset.GetRelayerRequest 3, // 13: loop.relayerset.RelayerSet.List:input_type -> loop.relayerset.ListAllRelayersRequest 8, // 14: loop.relayerset.RelayerSet.NewPluginProvider:input_type -> loop.relayerset.NewPluginProviderRequest 10, // 15: loop.relayerset.RelayerSet.NewContractReader:input_type -> loop.relayerset.NewContractReaderRequest - 12, // 16: loop.relayerset.RelayerSet.NewChainWriter:input_type -> loop.relayerset.NewChainWriterRequest + 12, // 16: loop.relayerset.RelayerSet.NewContractWriter:input_type -> loop.relayerset.NewContractWriterRequest 0, // 17: loop.relayerset.RelayerSet.StartRelayer:input_type -> loop.relayerset.RelayerId 0, // 18: loop.relayerset.RelayerSet.CloseRelayer:input_type -> loop.relayerset.RelayerId 0, // 19: loop.relayerset.RelayerSet.RelayerReady:input_type -> loop.relayerset.RelayerId @@ -1236,7 +1238,7 @@ var file_relayerset_proto_depIdxs = []int32{ 4, // 24: loop.relayerset.RelayerSet.List:output_type -> loop.relayerset.ListAllRelayersResponse 9, // 25: loop.relayerset.RelayerSet.NewPluginProvider:output_type -> loop.relayerset.NewPluginProviderResponse 11, // 26: loop.relayerset.RelayerSet.NewContractReader:output_type -> loop.relayerset.NewContractReaderResponse - 13, // 27: loop.relayerset.RelayerSet.NewChainWriter:output_type -> loop.relayerset.NewChainWriterResponse + 13, // 27: loop.relayerset.RelayerSet.NewContractWriter:output_type -> loop.relayerset.NewContractWriterResponse 19, // 28: loop.relayerset.RelayerSet.StartRelayer:output_type -> google.protobuf.Empty 19, // 29: loop.relayerset.RelayerSet.CloseRelayer:output_type -> google.protobuf.Empty 19, // 30: loop.relayerset.RelayerSet.RelayerReady:output_type -> google.protobuf.Empty @@ -1401,7 +1403,7 @@ func file_relayerset_proto_init() { } } file_relayerset_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewChainWriterRequest); i { + switch v := v.(*NewContractWriterRequest); i { case 0: return &v.state case 1: @@ -1413,7 +1415,7 @@ func file_relayerset_proto_init() { } } file_relayerset_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewChainWriterResponse); i { + switch v := v.(*NewContractWriterResponse); i { case 0: return &v.state case 1: diff --git a/pkg/loop/internal/pb/relayerset/relayerset.proto b/pkg/loop/internal/pb/relayerset/relayerset.proto index 5e1e4e441..0244c7127 100644 --- a/pkg/loop/internal/pb/relayerset/relayerset.proto +++ b/pkg/loop/internal/pb/relayerset/relayerset.proto @@ -67,13 +67,13 @@ message NewContractReaderResponse { uint32 contractReaderId = 1; } -message NewChainWriterRequest { +message NewContractWriterRequest { RelayerId relayerId = 1; - bytes chainWriterConfig = 2; + bytes contractWriterConfig = 2; } -message NewChainWriterResponse { - uint32 chainWriterId = 1; +message NewContractWriterResponse { + uint32 contractWriterId = 1; } message LatestHeadRequest { @@ -99,7 +99,7 @@ service RelayerSet { rpc List(ListAllRelayersRequest) returns (ListAllRelayersResponse) {} rpc NewPluginProvider(NewPluginProviderRequest) returns (NewPluginProviderResponse) {} rpc NewContractReader(NewContractReaderRequest) returns (NewContractReaderResponse) {} - rpc NewChainWriter(NewChainWriterRequest) returns (NewChainWriterResponse) {} + rpc NewContractWriter(NewContractWriterRequest) returns (NewContractWriterResponse) {} rpc StartRelayer(RelayerId) returns (google.protobuf.Empty) {} rpc CloseRelayer(RelayerId) returns (google.protobuf.Empty) {} diff --git a/pkg/loop/internal/pb/relayerset/relayerset_grpc.pb.go b/pkg/loop/internal/pb/relayerset/relayerset_grpc.pb.go index d922c51c0..21220a253 100644 --- a/pkg/loop/internal/pb/relayerset/relayerset_grpc.pb.go +++ b/pkg/loop/internal/pb/relayerset/relayerset_grpc.pb.go @@ -24,7 +24,7 @@ const ( RelayerSet_List_FullMethodName = "/loop.relayerset.RelayerSet/List" RelayerSet_NewPluginProvider_FullMethodName = "/loop.relayerset.RelayerSet/NewPluginProvider" RelayerSet_NewContractReader_FullMethodName = "/loop.relayerset.RelayerSet/NewContractReader" - RelayerSet_NewChainWriter_FullMethodName = "/loop.relayerset.RelayerSet/NewChainWriter" + RelayerSet_NewContractWriter_FullMethodName = "/loop.relayerset.RelayerSet/NewContractWriter" RelayerSet_StartRelayer_FullMethodName = "/loop.relayerset.RelayerSet/StartRelayer" RelayerSet_CloseRelayer_FullMethodName = "/loop.relayerset.RelayerSet/CloseRelayer" RelayerSet_RelayerReady_FullMethodName = "/loop.relayerset.RelayerSet/RelayerReady" @@ -41,7 +41,7 @@ type RelayerSetClient interface { List(ctx context.Context, in *ListAllRelayersRequest, opts ...grpc.CallOption) (*ListAllRelayersResponse, error) NewPluginProvider(ctx context.Context, in *NewPluginProviderRequest, opts ...grpc.CallOption) (*NewPluginProviderResponse, error) NewContractReader(ctx context.Context, in *NewContractReaderRequest, opts ...grpc.CallOption) (*NewContractReaderResponse, error) - NewChainWriter(ctx context.Context, in *NewChainWriterRequest, opts ...grpc.CallOption) (*NewChainWriterResponse, error) + NewContractWriter(ctx context.Context, in *NewContractWriterRequest, opts ...grpc.CallOption) (*NewContractWriterResponse, error) StartRelayer(ctx context.Context, in *RelayerId, opts ...grpc.CallOption) (*emptypb.Empty, error) CloseRelayer(ctx context.Context, in *RelayerId, opts ...grpc.CallOption) (*emptypb.Empty, error) RelayerReady(ctx context.Context, in *RelayerId, opts ...grpc.CallOption) (*emptypb.Empty, error) @@ -94,9 +94,9 @@ func (c *relayerSetClient) NewContractReader(ctx context.Context, in *NewContrac return out, nil } -func (c *relayerSetClient) NewChainWriter(ctx context.Context, in *NewChainWriterRequest, opts ...grpc.CallOption) (*NewChainWriterResponse, error) { - out := new(NewChainWriterResponse) - err := c.cc.Invoke(ctx, RelayerSet_NewChainWriter_FullMethodName, in, out, opts...) +func (c *relayerSetClient) NewContractWriter(ctx context.Context, in *NewContractWriterRequest, opts ...grpc.CallOption) (*NewContractWriterResponse, error) { + out := new(NewContractWriterResponse) + err := c.cc.Invoke(ctx, RelayerSet_NewContractWriter_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -165,7 +165,7 @@ type RelayerSetServer interface { List(context.Context, *ListAllRelayersRequest) (*ListAllRelayersResponse, error) NewPluginProvider(context.Context, *NewPluginProviderRequest) (*NewPluginProviderResponse, error) NewContractReader(context.Context, *NewContractReaderRequest) (*NewContractReaderResponse, error) - NewChainWriter(context.Context, *NewChainWriterRequest) (*NewChainWriterResponse, error) + NewContractWriter(context.Context, *NewContractWriterRequest) (*NewContractWriterResponse, error) StartRelayer(context.Context, *RelayerId) (*emptypb.Empty, error) CloseRelayer(context.Context, *RelayerId) (*emptypb.Empty, error) RelayerReady(context.Context, *RelayerId) (*emptypb.Empty, error) @@ -191,8 +191,8 @@ func (UnimplementedRelayerSetServer) NewPluginProvider(context.Context, *NewPlug func (UnimplementedRelayerSetServer) NewContractReader(context.Context, *NewContractReaderRequest) (*NewContractReaderResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method NewContractReader not implemented") } -func (UnimplementedRelayerSetServer) NewChainWriter(context.Context, *NewChainWriterRequest) (*NewChainWriterResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method NewChainWriter not implemented") +func (UnimplementedRelayerSetServer) NewContractWriter(context.Context, *NewContractWriterRequest) (*NewContractWriterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method NewContractWriter not implemented") } func (UnimplementedRelayerSetServer) StartRelayer(context.Context, *RelayerId) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method StartRelayer not implemented") @@ -297,20 +297,20 @@ func _RelayerSet_NewContractReader_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _RelayerSet_NewChainWriter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NewChainWriterRequest) +func _RelayerSet_NewContractWriter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NewContractWriterRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(RelayerSetServer).NewChainWriter(ctx, in) + return srv.(RelayerSetServer).NewContractWriter(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: RelayerSet_NewChainWriter_FullMethodName, + FullMethod: RelayerSet_NewContractWriter_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RelayerSetServer).NewChainWriter(ctx, req.(*NewChainWriterRequest)) + return srv.(RelayerSetServer).NewContractWriter(ctx, req.(*NewContractWriterRequest)) } return interceptor(ctx, in, info, handler) } @@ -447,8 +447,8 @@ var RelayerSet_ServiceDesc = grpc.ServiceDesc{ Handler: _RelayerSet_NewContractReader_Handler, }, { - MethodName: "NewChainWriter", - Handler: _RelayerSet_NewChainWriter_Handler, + MethodName: "NewContractWriter", + Handler: _RelayerSet_NewContractWriter_Handler, }, { MethodName: "StartRelayer", diff --git a/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader.go b/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader.go index 44cd9a94f..5b49a7afe 100644 --- a/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "iter" "reflect" "github.com/fxamacker/cbor/v2" @@ -280,6 +281,43 @@ func (c *Client) QueryKey(ctx context.Context, contract types.BoundContract, fil return convertSequencesFromProto(reply.Sequences, sequenceDataType) } +func (c *Client) QueryKeys(ctx context.Context, keyQueries []types.ContractKeyFilter, limitAndSort query.LimitAndSort) (iter.Seq2[string, types.Sequence], error) { + var filters []*pb.ContractKeyFilter + for _, keyQuery := range keyQueries { + _, asValueType := keyQuery.SequenceDataType.(*values.Value) + contract := convertBoundContractToProto(keyQuery.Contract) + + pbQueryFilter, err := convertQueryFilterToProto(keyQuery.KeyFilter, c.encodeWith) + if err != nil { + return nil, err + } + + filters = append(filters, &pb.ContractKeyFilter{ + Contract: contract, + Filter: pbQueryFilter, + AsValueType: asValueType, + }) + } + + pbLimitAndSort, err := convertLimitAndSortToProto(limitAndSort) + if err != nil { + return nil, err + } + + reply, err := c.grpc.QueryKeys( + ctx, + &pb.QueryKeysRequest{ + Filters: filters, + LimitAndSort: pbLimitAndSort, + }, + ) + if err != nil { + return nil, net.WrapRPCErr(err) + } + + return convertSequencesWithKeyFromProto(reply.Sequences, keyQueries) +} + func (c *Client) Bind(ctx context.Context, bindings []types.BoundContract) error { pbBindings := make([]*pb.BoundContract, len(bindings)) for i, b := range bindings { @@ -462,7 +500,7 @@ func (c *Server) BatchGetLatestValues(ctx context.Context, pbRequest *pb.BatchGe func (c *Server) QueryKey(ctx context.Context, request *pb.QueryKeyRequest) (*pb.QueryKeyReply, error) { contract := convertBoundContractFromProto(request.Contract) - queryFilter, err := convertQueryFiltersFromProto(request, contract, c.impl) + queryFilter, err := convertQueryFiltersFromProto(request.Filter, contract, c.impl) if err != nil { return nil, err } @@ -495,6 +533,46 @@ func (c *Server) QueryKey(ctx context.Context, request *pb.QueryKeyRequest) (*pb return &pb.QueryKeyReply{Sequences: pbSequences}, nil } +func (c *Server) QueryKeys(ctx context.Context, request *pb.QueryKeysRequest) (*pb.QueryKeysReply, error) { + var filters []types.ContractKeyFilter + for _, keyQuery := range request.Filters { + contract := convertBoundContractFromProto(keyQuery.Contract) + + queryFilter, err := convertQueryFiltersFromProto(keyQuery.Filter, contract, c.impl) + if err != nil { + return nil, err + } + + sequenceDataType, err := getContractEncodedType(contract.ReadIdentifier(queryFilter.Key), c.impl, false) + if err != nil { + return nil, err + } + + filters = append(filters, types.ContractKeyFilter{ + Contract: contract, + KeyFilter: queryFilter, + SequenceDataType: sequenceDataType, + }) + } + + limitAndSort, err := convertLimitAndSortFromProto(request.GetLimitAndSort()) + if err != nil { + return nil, err + } + + sequences, err := c.impl.QueryKeys(ctx, filters, limitAndSort) + if err != nil { + return nil, err + } + + pbSequences, err := convertSequencesWithKeyToVersionedBytesProto(sequences, request.Filters, c.encodeWith) + if err != nil { + return nil, err + } + + return &pb.QueryKeysReply{Sequences: pbSequences}, nil +} + func (c *Server) Bind(ctx context.Context, bindings *pb.BindRequest) (*emptypb.Empty, error) { tBindings := make([]types.BoundContract, len(bindings.Bindings)) for i, b := range bindings.Bindings { @@ -758,6 +836,42 @@ func convertSequencesToVersionedBytesProto(sequences []types.Sequence, version E return pbSequences, nil } +func convertSequencesWithKeyToVersionedBytesProto(sequences iter.Seq2[string, types.Sequence], filters []*pb.ContractKeyFilter, encodeWith EncodingVersion) ([]*pb.SequenceWithKey, error) { + keyToEncodingVersion := make(map[string]EncodingVersion) + for _, filter := range filters { + if filter.AsValueType { + keyToEncodingVersion[filter.Filter.Key] = ValuesEncodingVersion + } else { + keyToEncodingVersion[filter.Filter.Key] = encodeWith + } + } + + var pbSequences []*pb.SequenceWithKey + for key, sequence := range sequences { + version, ok := keyToEncodingVersion[key] + if !ok { + return nil, fmt.Errorf("missing encoding version for key %s", key) + } + + versionedSequenceDataType, err := EncodeVersionedBytes(sequence.Data, version) + if err != nil { + return nil, err + } + pbSequence := &pb.SequenceWithKey{ + Key: key, + SequenceCursor: sequence.Cursor, + Head: &pb.Head{ + Height: sequence.Height, + Hash: sequence.Hash, + Timestamp: sequence.Timestamp, + }, + Data: versionedSequenceDataType, + } + pbSequences = append(pbSequences, pbSequence) + } + return pbSequences, nil +} + func parseBatchGetLatestValuesReply(request types.BatchGetLatestValuesRequest, reply *pb.BatchGetLatestValuesReply) (types.BatchGetLatestValuesResult, error) { if reply == nil { return nil, fmt.Errorf("received nil reply from grpc BatchGetLatestValues") @@ -844,8 +958,7 @@ func convertBoundContractFromProto(contract *pb.BoundContract) types.BoundContra } } -func convertQueryFiltersFromProto(request *pb.QueryKeyRequest, contract types.BoundContract, impl types.ContractReader) (query.KeyFilter, error) { - pbQueryFilters := request.Filter +func convertQueryFiltersFromProto(pbQueryFilters *pb.QueryKeyFilter, contract types.BoundContract, impl types.ContractReader) (query.KeyFilter, error) { queryFilter := query.KeyFilter{Key: pbQueryFilters.Key} for _, pbQueryFilter := range pbQueryFilters.Expression { expression, err := convertExpressionFromProto(pbQueryFilter, contract, queryFilter.Key, impl) @@ -949,16 +1062,9 @@ func convertLimitAndSortFromProto(limitAndSort *pb.LimitAndSort) (query.LimitAnd func convertSequencesFromProto(pbSequences []*pb.Sequence, sequenceDataType any) ([]types.Sequence, error) { sequences := make([]types.Sequence, len(pbSequences)) - seqTypeOf := reflect.TypeOf(sequenceDataType) - - // get the non-pointer data type for the sequence data - nonPointerType := seqTypeOf - if seqTypeOf.Kind() == reflect.Pointer { - nonPointerType = seqTypeOf.Elem() - } - - if nonPointerType.Kind() == reflect.Pointer { - return nil, fmt.Errorf("%w: sequenceDataType does not support pointers to pointers", types.ErrInvalidType) + seqTypeOf, nonPointerType, err := getSequenceTypeInformation(sequenceDataType) + if err != nil { + return nil, err } for idx, pbSequence := range pbSequences { @@ -986,6 +1092,78 @@ func convertSequencesFromProto(pbSequences []*pb.Sequence, sequenceDataType any) return sequences, nil } +func getSequenceTypeInformation(sequenceDataType any) (reflect.Type, reflect.Type, error) { + seqTypeOf := reflect.TypeOf(sequenceDataType) + + // get the non-pointer data type for the sequence data + nonPointerType := seqTypeOf + if seqTypeOf.Kind() == reflect.Pointer { + nonPointerType = seqTypeOf.Elem() + } + + if nonPointerType.Kind() == reflect.Pointer { + return nil, nil, fmt.Errorf("%w: sequenceDataType does not support pointers to pointers", types.ErrInvalidType) + } + return seqTypeOf, nonPointerType, nil +} + +func convertSequencesWithKeyFromProto(pbSequences []*pb.SequenceWithKey, keyQueries []types.ContractKeyFilter) (iter.Seq2[string, types.Sequence], error) { + type sequenceWithKey struct { + Key string + Sequence types.Sequence + } + + sequencesWithKey := make([]sequenceWithKey, len(pbSequences)) + + keyToSeqTypeOf := make(map[string]reflect.Type) + keyToNonPointerType := make(map[string]reflect.Type) + + for _, keyQuery := range keyQueries { + seqTypeOf, nonPointerType, err := getSequenceTypeInformation(keyQuery.SequenceDataType) + if err != nil { + return nil, err + } + + keyToSeqTypeOf[keyQuery.Key] = seqTypeOf + keyToNonPointerType[keyQuery.Key] = nonPointerType + } + + for idx, pbSequence := range pbSequences { + seqTypeOf, nonPointerType := keyToSeqTypeOf[pbSequence.Key], keyToNonPointerType[pbSequence.Key] + + cpy := reflect.New(nonPointerType).Interface() + if err := DecodeVersionedBytes(cpy, pbSequence.Data); err != nil { + return nil, err + } + + // match provided data type either as pointer or non-pointer + if seqTypeOf.Kind() != reflect.Pointer { + cpy = reflect.Indirect(reflect.ValueOf(cpy)).Interface() + } + pbSeq := pbSequences[idx] + sequencesWithKey[idx] = sequenceWithKey{ + Key: pbSeq.Key, + Sequence: types.Sequence{ + Cursor: pbSeq.SequenceCursor, + Head: types.Head{ + Height: pbSeq.Head.Height, + Hash: pbSeq.Head.Hash, + Timestamp: pbSeq.Head.Timestamp, + }, + Data: cpy, + }, + } + } + + return func(yield func(string, types.Sequence) bool) { + for _, s := range sequencesWithKey { + if !yield(s.Key, s.Sequence) { + return + } + } + }, nil +} + func RegisterContractReaderService(s *grpc.Server, contractReader types.ContractReader) { service := goplugin.ServiceServer{Srv: contractReader} pb.RegisterServiceServer(s, &service) diff --git a/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader_test.go b/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader_test.go index be2b1f7b7..88a87031c 100644 --- a/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader_test.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractreader/contract_reader_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "iter" "math/big" "reflect" "sort" @@ -29,7 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-common/pkg/values" - . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" ) func TestVersionedBytesFunctions(t *testing.T) { @@ -299,14 +300,14 @@ type fakeContractReaderInterfaceTester struct { interfaceTesterBase TestSelectionSupport impl types.ContractReader - cw fakeChainWriter + cw fakeContractWriter } func (it *fakeContractReaderInterfaceTester) Setup(_ *testing.T) { fake, ok := it.impl.(*fakeContractReader) if ok { fake.vals = make(map[string][]valConfidencePair) - fake.triggers = make(map[string][]eventConfidencePair) + fake.triggers = newEventsRecorder() fake.stored = make(map[string][]TestStruct) } } @@ -315,7 +316,7 @@ func (it *fakeContractReaderInterfaceTester) GetContractReader(_ *testing.T) typ return it.impl } -func (it *fakeContractReaderInterfaceTester) GetChainWriter(_ *testing.T) types.ChainWriter { +func (it *fakeContractReaderInterfaceTester) GetContractWriter(_ *testing.T) types.ContractWriter { it.cw.cr = it.impl.(*fakeContractReader) return &it.cw } @@ -351,22 +352,95 @@ type eventConfidencePair struct { confidenceLevel primitives.ConfidenceLevel } +type dynamicTopicEventConfidencePair struct { + someDynamicTopicEvent SomeDynamicTopicEvent + confidenceLevel primitives.ConfidenceLevel +} +type event struct { + contractID string + event any + confidenceLevel primitives.ConfidenceLevel + eventType string +} + +type eventsRecorder struct { + mux sync.Mutex + events []event +} + +func newEventsRecorder() *eventsRecorder { + return &eventsRecorder{} +} + +func (e *eventsRecorder) RecordEvent(contractID string, evt any, confidenceLevel primitives.ConfidenceLevel, eventType string) error { + e.mux.Lock() + defer e.mux.Unlock() + + switch eventType { + case EventName: + _, ok := evt.(TestStruct) + if !ok { + return fmt.Errorf("unexpected event type %T", evt) + } + case DynamicTopicEventName: + _, ok := evt.(SomeDynamicTopicEvent) + if !ok { + return fmt.Errorf("unexpected event type %T", evt) + } + + } + + e.events = append(e.events, event{contractID: contractID, event: evt, confidenceLevel: confidenceLevel, eventType: eventType}) + + return nil +} + +func (e *eventsRecorder) setConfidenceLevelOnAllEvents(confidenceLevel primitives.ConfidenceLevel) { + e.mux.Lock() + defer e.mux.Unlock() + + for i := range e.events { + e.events[i].confidenceLevel = confidenceLevel + } +} + +func (e *eventsRecorder) getEvents(filters ...func(event) bool) []event { + e.mux.Lock() + defer e.mux.Unlock() + + events := make([]event, 0) + for _, event := range e.events { + match := true + for _, filter := range filters { + if !filter(event) { + match = false + break + } + } + if match { + events = append(events, event) + } + } + + return events +} + type fakeContractReader struct { types.UnimplementedContractReader fakeTypeProvider vals map[string][]valConfidencePair - triggers map[string][]eventConfidencePair + triggers *eventsRecorder stored map[string][]TestStruct batchStored BatchCallEntry lock sync.Mutex } -type fakeChainWriter struct { - types.ChainWriter +type fakeContractWriter struct { + types.ContractWriter cr *fakeContractReader } -func (f *fakeChainWriter) SubmitTransaction(_ context.Context, contractName, method string, args any, transactionID string, toAddress string, meta *types.TxMeta, value *big.Int) error { +func (f *fakeContractWriter) SubmitTransaction(_ context.Context, contractName, method string, args any, transactionID string, toAddress string, meta *types.TxMeta, value *big.Int) error { contractID := toAddress + "-" + contractName switch method { case MethodSettingStruct: @@ -382,12 +456,14 @@ func (f *fakeChainWriter) SubmitTransaction(_ context.Context, contractName, met } f.cr.SetUintLatestValue(contractID, v.Value, ExpectedGetLatestValueArgs{}) case MethodTriggeringEvent: - v, ok := args.(TestStruct) - if !ok { - return fmt.Errorf("unexpected type %T", args) + if err := f.cr.triggers.RecordEvent(contractID, args, primitives.Unconfirmed, EventName); err != nil { + return fmt.Errorf("failed to record event: %w", err) + } + case MethodTriggeringEventWithDynamicTopic: + if err := f.cr.triggers.RecordEvent(contractID, args, primitives.Unconfirmed, DynamicTopicEventName); err != nil { + return fmt.Errorf("failed to record event: %w", err) } - f.cr.SetTrigger(contractID, &v) - case "batchChainWrite": + case "batchContractWrite": v, ok := args.(BatchCallEntry) if !ok { return fmt.Errorf("unexpected type %T", args) @@ -400,11 +476,11 @@ func (f *fakeChainWriter) SubmitTransaction(_ context.Context, contractName, met return nil } -func (f *fakeChainWriter) GetTransactionStatus(ctx context.Context, transactionID string) (types.TransactionStatus, error) { +func (f *fakeContractWriter) GetTransactionStatus(ctx context.Context, transactionID string) (types.TransactionStatus, error) { return types.Finalized, nil } -func (f *fakeChainWriter) GetFeeComponents(ctx context.Context) (*types.ChainFeeComponents, error) { +func (f *fakeContractWriter) GetFeeComponents(ctx context.Context) (*types.ChainFeeComponents, error) { return &types.ChainFeeComponents{}, nil } @@ -495,14 +571,17 @@ func (f *fakeContractReader) GetLatestValue(_ context.Context, readIdentifier st f.lock.Lock() defer f.lock.Unlock() - triggers := f.triggers[contractName] - if len(triggers) == 0 { + events := f.triggers.getEvents(func(e event) bool { + return e.contractID == contractName && e.eventType == EventName + }) + + if len(events) == 0 { return types.ErrNotFound } - for i := len(triggers) - 1; i >= 0; i-- { - if triggers[i].confidenceLevel == confidenceLevel { - *returnVal.(*TestStruct) = triggers[i].testStruct + for i := len(events) - 1; i >= 0; i-- { + if events[i].confidenceLevel == confidenceLevel { + *returnVal.(*TestStruct) = events[i].event.(TestStruct) return nil } } @@ -512,14 +591,33 @@ func (f *fakeContractReader) GetLatestValue(_ context.Context, readIdentifier st f.lock.Lock() defer f.lock.Unlock() param := params.(*FilterEventParams) - triggers := f.triggers[contractName] + triggers := f.triggers.getEvents(func(e event) bool { return e.contractID == contractName && e.eventType == EventName }) for i := len(triggers) - 1; i >= 0; i-- { - if *triggers[i].testStruct.Field == param.Field { - *returnVal.(*TestStruct) = triggers[i].testStruct + testStruct := triggers[i].event.(TestStruct) + if *testStruct.Field == param.Field { + *returnVal.(*TestStruct) = testStruct return nil } } return types.ErrNotFound + } else if strings.HasSuffix(readIdentifier, DynamicTopicEventName) { + f.lock.Lock() + defer f.lock.Unlock() + + triggers := f.triggers.getEvents(func(e event) bool { return e.contractID == contractName && e.eventType == DynamicTopicEventName }) + + if len(triggers) == 0 { + return types.ErrNotFound + } + + for i := len(triggers) - 1; i >= 0; i-- { + if triggers[i].confidenceLevel == confidenceLevel { + *returnVal.(*SomeDynamicTopicEvent) = triggers[i].event.(SomeDynamicTopicEvent) + return nil + } + } + + return fmt.Errorf("%w: no event with %s confidence was found ", types.ErrNotFound, confidenceLevel) } else if !strings.HasSuffix(readIdentifier, MethodTakingLatestParamsReturningTestStruct) { return errors.New("unknown method " + readIdentifier) } @@ -614,112 +712,166 @@ func (f *fakeContractReader) BatchGetLatestValues(_ context.Context, request typ return result, nil } -func (f *fakeContractReader) QueryKey(_ context.Context, bc types.BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceType any) ([]types.Sequence, error) { - _, isValueType := sequenceType.(*values.Value) - if filter.Key == EventName { - f.lock.Lock() - defer f.lock.Unlock() - if len(f.triggers) == 0 { - return []types.Sequence{}, nil +func (f *fakeContractReader) QueryKey(ctx context.Context, bc types.BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceType any) ([]types.Sequence, error) { + seqsIter, err := f.QueryKeys(ctx, []types.ContractKeyFilter{types.ContractKeyFilter{ + KeyFilter: filter, + Contract: bc, + SequenceDataType: sequenceType, + }}, limitAndSort) + + if err != nil { + return nil, err + } + + if seqsIter != nil { + var seqs []types.Sequence + for _, seq := range seqsIter { + seqs = append(seqs, seq) } - var sequences []types.Sequence - for idx, trigger := range f.triggers[bc.String()] { - doAppend := true - for _, expr := range filter.Expressions { - if primitive, ok := expr.Primitive.(*primitives.Comparator); ok { - if len(primitive.ValueComparators) == 0 { - return nil, fmt.Errorf("value comparator for %s should not be empty", primitive.Name) - } - if primitive.Name == "Field" { - for _, valComp := range primitive.ValueComparators { - doAppend = doAppend && Compare(*trigger.testStruct.Field, *valComp.Value.(*int32), valComp.Operator) - } + return seqs, nil + } + + return nil, nil +} + +type sequenceWithEventType struct { + eventType string + sequence types.Sequence +} + +func (f *fakeContractReader) QueryKeys(_ context.Context, filters []types.ContractKeyFilter, limitAndSort query.LimitAndSort) (iter.Seq2[string, types.Sequence], error) { + f.lock.Lock() + defer f.lock.Unlock() + + supportedEventTypes := map[string]struct{}{EventName: {}, DynamicTopicEventName: {}} + + for _, filter := range filters { + if _, ok := supportedEventTypes[filter.Key]; !ok { + return nil, fmt.Errorf("unsupported event type %s", filter.Key) + } + } + + if len(filters) > 1 { + fmt.Printf("filters: %v\n", filters) + } + + isValueType := false + eventTypeToFilter := map[string]types.ContractKeyFilter{} + for _, filter := range filters { + eventTypeToFilter[filter.Key] = filter + _, isValueType = filter.SequenceDataType.(*values.Value) + } + + events := f.triggers.getEvents(func(e event) bool { + filter := eventTypeToFilter[e.eventType] + + if e.contractID != filter.Contract.String() { + return false + } + _, filterExistsForType := eventTypeToFilter[e.eventType] + + return filterExistsForType + }) + + var sequences []sequenceWithEventType + for idx, trigger := range events { + filter := eventTypeToFilter[trigger.eventType] + + doAppend := true + for _, expr := range filter.Expressions { + if primitive, ok := expr.Primitive.(*primitives.Comparator); ok { + if len(primitive.ValueComparators) == 0 { + return nil, fmt.Errorf("value comparator for %s should not be empty", primitive.Name) + } + if primitive.Name == "Field" { + for _, valComp := range primitive.ValueComparators { + doAppend = doAppend && Compare(*trigger.event.(TestStruct).Field, *valComp.Value.(*int32), valComp.Operator) } } } + } - var skipAppend bool - if limitAndSort.HasCursorLimit() { - cursor, err := strconv.Atoi(limitAndSort.Limit.Cursor) - if err != nil { - return nil, err - } + var skipAppend bool + if limitAndSort.HasCursorLimit() { + cursor, err := strconv.Atoi(limitAndSort.Limit.Cursor) + if err != nil { + return nil, err + } - // assume CursorFollowing order for now - if cursor >= idx { - skipAppend = true - } + // assume CursorFollowing order for now + if cursor >= idx { + skipAppend = true } + } - if (len(filter.Expressions) == 0 || doAppend) && !skipAppend { - if isValueType { - value, err := values.Wrap(trigger.testStruct) - if err != nil { - return nil, err - } - sequences = append(sequences, types.Sequence{Cursor: strconv.Itoa(idx), Data: &value}) - } else { - sequences = append(sequences, types.Sequence{Cursor: fmt.Sprintf("%d", idx), Data: trigger.testStruct}) + if (len(eventTypeToFilter[trigger.eventType].Expressions) == 0 || doAppend) && !skipAppend { + if isValueType { + value, err := values.Wrap(trigger.event) + if err != nil { + return nil, err } + sequences = append(sequences, sequenceWithEventType{eventType: trigger.eventType, sequence: types.Sequence{Cursor: strconv.Itoa(idx), Data: &value}}) + } else { + sequences = append(sequences, sequenceWithEventType{eventType: trigger.eventType, sequence: types.Sequence{Cursor: fmt.Sprintf("%d", idx), Data: trigger.event}}) } + } - if limitAndSort.Limit.Count > 0 && len(sequences) >= int(limitAndSort.Limit.Count) { - break - } + if limitAndSort.Limit.Count > 0 && len(sequences) >= int(limitAndSort.Limit.Count) { + break } + } - if isValueType { - if !limitAndSort.HasSequenceSort() && !limitAndSort.HasCursorLimit() { - sort.Slice(sequences, func(i, j int) bool { - valI := *sequences[i].Data.(*values.Value) - valJ := *sequences[j].Data.(*values.Value) + if isValueType { + if !limitAndSort.HasSequenceSort() && !limitAndSort.HasCursorLimit() { + sort.Slice(sequences, func(i, j int) bool { + valI := *sequences[i].sequence.Data.(*values.Value) + valJ := *sequences[j].sequence.Data.(*values.Value) - mapI := valI.(*values.Map) - mapJ := valJ.(*values.Map) + mapI := valI.(*values.Map) + mapJ := valJ.(*values.Map) - if mapI.Underlying["Field"] == nil || mapJ.Underlying["Field"] == nil { - return false - } - var iVal int32 - err := mapI.Underlying["Field"].UnwrapTo(&iVal) - if err != nil { - panic(err) - } + if mapI.Underlying["Field"] == nil || mapJ.Underlying["Field"] == nil { + return false + } + var iVal int32 + err := mapI.Underlying["Field"].UnwrapTo(&iVal) + if err != nil { + panic(err) + } - var jVal int32 - err = mapJ.Underlying["Field"].UnwrapTo(&jVal) - if err != nil { - panic(err) - } + var jVal int32 + err = mapJ.Underlying["Field"].UnwrapTo(&jVal) + if err != nil { + panic(err) + } - return iVal > jVal - }) - } - } else { - if !limitAndSort.HasSequenceSort() && !limitAndSort.HasCursorLimit() { - sort.Slice(sequences, func(i, j int) bool { - if sequences[i].Data.(TestStruct).Field == nil || sequences[j].Data.(TestStruct).Field == nil { - return false - } - return *sequences[i].Data.(TestStruct).Field > *sequences[j].Data.(TestStruct).Field - }) + return iVal > jVal + }) + } + } else { + if !limitAndSort.HasSequenceSort() && !limitAndSort.HasCursorLimit() { + if len(eventTypeToFilter) == 1 { + if _, ok := eventTypeToFilter[EventName]; ok { + sort.Slice(sequences, func(i, j int) bool { + if sequences[i].sequence.Data.(TestStruct).Field == nil || sequences[j].sequence.Data.(TestStruct).Field == nil { + return false + } + return *sequences[i].sequence.Data.(TestStruct).Field > *sequences[j].sequence.Data.(TestStruct).Field + }) + } } } - - return sequences, nil } - return nil, nil -} -func (f *fakeContractReader) SetTrigger(contractID string, testStruct *TestStruct) { - f.lock.Lock() - defer f.lock.Unlock() - if _, ok := f.triggers[contractID]; !ok { - f.triggers[contractID] = []eventConfidencePair{} - } + return func(yield func(string, types.Sequence) bool) { + for _, s := range sequences { + if !yield(s.eventType, s.sequence) { + return + } + } + }, nil - f.triggers[contractID] = append(f.triggers[contractID], eventConfidencePair{testStruct: *testStruct, confidenceLevel: primitives.Unconfirmed}) } func (f *fakeContractReader) GenerateBlocksTillConfidenceLevel(_ *testing.T, _, _ string, confidenceLevel primitives.ConfidenceLevel) { @@ -732,11 +884,7 @@ func (f *fakeContractReader) GenerateBlocksTillConfidenceLevel(_ *testing.T, _, } } - for contractID, triggers := range f.triggers { - for i, trigger := range triggers { - f.triggers[contractID][i] = eventConfidencePair{testStruct: trigger.testStruct, confidenceLevel: confidenceLevel} - } - } + f.triggers.setConfidenceLevelOnAllEvents(confidenceLevel) } type errContractReader struct { diff --git a/pkg/loop/internal/relayer/pluginprovider/contractreader/helper_test.go b/pkg/loop/internal/relayer/pluginprovider/contractreader/helper_test.go index 9d87f581c..aa66b4edb 100644 --- a/pkg/loop/internal/relayer/pluginprovider/contractreader/helper_test.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractreader/helper_test.go @@ -99,6 +99,11 @@ func (fakeTypeProvider) CreateContractType(readName string, isEncode bool) (any, return &FilterEventParams{}, nil } return &TestStruct{}, nil + case strings.HasSuffix(readName, DynamicTopicEventName), strings.HasSuffix(readName, EventWithFilterName): + if isEncode { + return &FilterEventParams{}, nil + } + return &SomeDynamicTopicEvent{}, nil case strings.HasSuffix(readName, EventNameField): if isEncode { var typ int32 diff --git a/pkg/loop/internal/relayer/pluginprovider/contractreader/test/contract_reader_loop_tester.go b/pkg/loop/internal/relayer/pluginprovider/contractreader/test/contract_reader_loop_tester.go index 427552d80..8bd159de5 100644 --- a/pkg/loop/internal/relayer/pluginprovider/contractreader/test/contract_reader_loop_tester.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractreader/test/contract_reader_loop_tester.go @@ -33,7 +33,7 @@ func TestAllEncodings(t *testing.T, test func(contractreader.EncodingVersion) fu type LoopTesterOpt func(*contractReaderLoopTester) -// WrapContractReaderTesterForLoop allows you to test a [types.ContractReader] and [types.ChainWriter] implementation behind a LOOP server +// WrapContractReaderTesterForLoop allows you to test a [types.ContractReader] and [types.ContractWriter] implementation behind a LOOP server func WrapContractReaderTesterForLoop(wrapped ChainComponentsInterfaceTester[*testing.T], opts ...LoopTesterOpt) ChainComponentsInterfaceTester[*testing.T] { tester := &contractReaderLoopTester{ ChainComponentsInterfaceTester: wrapped, diff --git a/pkg/loop/internal/relayer/pluginprovider/chainwriter/chain_writer.go b/pkg/loop/internal/relayer/pluginprovider/contractwriter/contract_writer.go similarity index 88% rename from pkg/loop/internal/relayer/pluginprovider/chainwriter/chain_writer.go rename to pkg/loop/internal/relayer/pluginprovider/contractwriter/contract_writer.go index f1f39b78d..f5fe32471 100644 --- a/pkg/loop/internal/relayer/pluginprovider/chainwriter/chain_writer.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractwriter/contract_writer.go @@ -1,4 +1,4 @@ -package chainwriter +package contractwriter import ( "context" @@ -14,20 +14,20 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" ) -var _ types.ChainWriter = (*Client)(nil) +var _ types.ContractWriter = (*Client)(nil) type ClientOpt func(*Client) type Client struct { *goplugin.ServiceClient - grpc pb.ChainWriterClient + grpc pb.ContractWriterClient encodeWith contractreader.EncodingVersion } func NewClient(b *net.BrokerExt, cc grpc.ClientConnInterface, opts ...ClientOpt) *Client { client := &Client{ ServiceClient: goplugin.NewServiceClient(b, cc), - grpc: pb.NewChainWriterClient(cc), + grpc: pb.NewContractWriterClient(cc), encodeWith: contractreader.DefaultEncodingVersion, } @@ -91,17 +91,17 @@ func (c *Client) GetFeeComponents(ctx context.Context) (*types.ChainFeeComponent // Server. -var _ pb.ChainWriterServer = (*Server)(nil) +var _ pb.ContractWriterServer = (*Server)(nil) type ServerOpt func(*Server) type Server struct { - pb.UnimplementedChainWriterServer - impl types.ChainWriter + pb.UnimplementedContractWriterServer + impl types.ContractWriter encodeWith contractreader.EncodingVersion } -func NewServer(impl types.ChainWriter, opts ...ServerOpt) pb.ChainWriterServer { +func NewServer(impl types.ContractWriter, opts ...ServerOpt) pb.ContractWriterServer { server := &Server{ impl: impl, encodeWith: contractreader.DefaultEncodingVersion, @@ -150,6 +150,6 @@ func (s *Server) GetFeeComponents(ctx context.Context, _ *emptypb.Empty) (*pb.Ge }, nil } -func RegisterChainWriterService(s *grpc.Server, chainWriter types.ChainWriter) { - pb.RegisterServiceServer(s, &goplugin.ServiceServer{Srv: chainWriter}) +func RegisterContractWriterService(s *grpc.Server, contractWriter types.ContractWriter) { + pb.RegisterServiceServer(s, &goplugin.ServiceServer{Srv: contractWriter}) } diff --git a/pkg/loop/internal/relayer/pluginprovider/chainwriter/converters.go b/pkg/loop/internal/relayer/pluginprovider/contractwriter/converters.go similarity index 97% rename from pkg/loop/internal/relayer/pluginprovider/chainwriter/converters.go rename to pkg/loop/internal/relayer/pluginprovider/contractwriter/converters.go index 732e0c199..1a21d6bb3 100644 --- a/pkg/loop/internal/relayer/pluginprovider/chainwriter/converters.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractwriter/converters.go @@ -1,4 +1,4 @@ -package chainwriter +package contractwriter import ( "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb" diff --git a/pkg/loop/internal/relayer/pluginprovider/chainwriter/converters_test.go b/pkg/loop/internal/relayer/pluginprovider/contractwriter/converters_test.go similarity index 66% rename from pkg/loop/internal/relayer/pluginprovider/chainwriter/converters_test.go rename to pkg/loop/internal/relayer/pluginprovider/contractwriter/converters_test.go index 6e41e42fa..43539a2f9 100644 --- a/pkg/loop/internal/relayer/pluginprovider/chainwriter/converters_test.go +++ b/pkg/loop/internal/relayer/pluginprovider/contractwriter/converters_test.go @@ -1,4 +1,4 @@ -package chainwriter_test +package contractwriter_test import ( "math/big" @@ -7,36 +7,36 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb" - "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainwriter" + "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractwriter" "github.com/smartcontractkit/chainlink-common/pkg/types" ) func TestTxMetaFromProto(t *testing.T) { t.Run("with nil meta", func(t *testing.T) { - meta := chainwriter.TxMetaFromProto(nil) + meta := contractwriter.TxMetaFromProto(nil) require.Nil(t, meta) }) t.Run("with nil workflow id", func(t *testing.T) { - meta := chainwriter.TxMetaFromProto(&pb.TransactionMeta{}) + meta := contractwriter.TxMetaFromProto(&pb.TransactionMeta{}) require.NotNil(t, meta) require.Nil(t, meta.WorkflowExecutionID) }) t.Run("with workflow id", func(t *testing.T) { - meta := chainwriter.TxMetaFromProto(&pb.TransactionMeta{WorkflowExecutionId: "workflow-id"}) + meta := contractwriter.TxMetaFromProto(&pb.TransactionMeta{WorkflowExecutionId: "workflow-id"}) require.NotNil(t, meta) require.Equal(t, "workflow-id", *meta.WorkflowExecutionID) }) t.Run("without gas limit", func(t *testing.T) { - meta := chainwriter.TxMetaFromProto(&pb.TransactionMeta{}) + meta := contractwriter.TxMetaFromProto(&pb.TransactionMeta{}) require.NotNil(t, meta) require.Nil(t, meta.GasLimit) }) t.Run("with gas limit", func(t *testing.T) { - meta := chainwriter.TxMetaFromProto(&pb.TransactionMeta{GasLimit: pb.NewBigIntFromInt(big.NewInt(10))}) + meta := contractwriter.TxMetaFromProto(&pb.TransactionMeta{GasLimit: pb.NewBigIntFromInt(big.NewInt(10))}) require.NotNil(t, meta) require.Equal(t, big.NewInt(10), meta.GasLimit) }) @@ -44,31 +44,31 @@ func TestTxMetaFromProto(t *testing.T) { func TestTxMetaToProto(t *testing.T) { t.Run("with nil meta", func(t *testing.T) { - proto := chainwriter.TxMetaToProto(nil) + proto := contractwriter.TxMetaToProto(nil) require.Nil(t, proto) }) t.Run("with empty workflow id", func(t *testing.T) { - proto := chainwriter.TxMetaToProto(&types.TxMeta{}) + proto := contractwriter.TxMetaToProto(&types.TxMeta{}) require.NotNil(t, proto) require.Empty(t, proto.WorkflowExecutionId) }) t.Run("with workflow id", func(t *testing.T) { workflowID := "workflow-id" - proto := chainwriter.TxMetaToProto(&types.TxMeta{WorkflowExecutionID: &workflowID}) + proto := contractwriter.TxMetaToProto(&types.TxMeta{WorkflowExecutionID: &workflowID}) require.NotNil(t, proto) require.Equal(t, workflowID, proto.WorkflowExecutionId) }) t.Run("without gas limit", func(t *testing.T) { - proto := chainwriter.TxMetaToProto(&types.TxMeta{}) + proto := contractwriter.TxMetaToProto(&types.TxMeta{}) require.NotNil(t, proto) require.Empty(t, proto.GasLimit) }) t.Run("with gas limit", func(t *testing.T) { - proto := chainwriter.TxMetaToProto(&types.TxMeta{GasLimit: big.NewInt(10)}) + proto := contractwriter.TxMetaToProto(&types.TxMeta{GasLimit: big.NewInt(10)}) require.NotNil(t, proto) require.Equal(t, big.NewInt(10), proto.GasLimit.Int()) }) diff --git a/pkg/loop/internal/relayer/relayer.go b/pkg/loop/internal/relayer/relayer.go index 97cdc35e6..e15470c3b 100644 --- a/pkg/loop/internal/relayer/relayer.go +++ b/pkg/loop/internal/relayer/relayer.go @@ -17,8 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/goplugin" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/net" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb" - "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainwriter" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractreader" + "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractwriter" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/ext/ccip" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/ext/median" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/ext/mercury" @@ -195,15 +195,15 @@ func newRelayerClient(b *net.BrokerExt, conn grpc.ClientConnInterface) *relayerC return &relayerClient{b, goplugin.NewServiceClient(b, conn), pb.NewRelayerClient(conn)} } -func (r *relayerClient) NewChainWriter(_ context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { - cwc := r.NewClientConn("ChainWriter", func(ctx context.Context) (uint32, net.Resources, error) { - reply, err := r.relayer.NewChainWriter(ctx, &pb.NewChainWriterRequest{ChainWriterConfig: chainWriterConfig}) +func (r *relayerClient) NewContractWriter(_ context.Context, contractWriterConfig []byte) (types.ContractWriter, error) { + cwc := r.NewClientConn("ContractWriter", func(ctx context.Context) (uint32, net.Resources, error) { + reply, err := r.relayer.NewContractWriter(ctx, &pb.NewContractWriterRequest{ContractWriterConfig: contractWriterConfig}) if err != nil { return 0, nil, err } - return reply.ChainWriterID, nil, nil + return reply.ContractWriterID, nil, nil }) - return chainwriter.NewClient(r.WithName("ChainWriterClient"), cwc), nil + return contractwriter.NewClient(r.WithName("ContractWriterClient"), cwc), nil } func (r *relayerClient) NewContractReader(_ context.Context, contractReaderConfig []byte) (types.ContractReader, error) { @@ -377,8 +377,8 @@ func newChainRelayerServer(impl looptypes.Relayer, b *net.BrokerExt) *relayerSer return &relayerServer{impl: impl, BrokerExt: b.WithName("ChainRelayerServer")} } -func (r *relayerServer) NewChainWriter(ctx context.Context, request *pb.NewChainWriterRequest) (*pb.NewChainWriterReply, error) { - cw, err := r.impl.NewChainWriter(ctx, request.GetChainWriterConfig()) +func (r *relayerServer) NewContractWriter(ctx context.Context, request *pb.NewContractWriterRequest) (*pb.NewContractWriterReply, error) { + cw, err := r.impl.NewContractWriter(ctx, request.GetContractWriterConfig()) if err != nil { return nil, err } @@ -387,15 +387,15 @@ func (r *relayerServer) NewChainWriter(ctx context.Context, request *pb.NewChain return nil, err } - const name = "ChainWriter" + const name = "ContractWriter" id, _, err := r.ServeNew(name, func(s *grpc.Server) { - chainwriter.RegisterChainWriterService(s, cw) + contractwriter.RegisterContractWriterService(s, cw) }, net.Resource{Closer: cw, Name: name}) if err != nil { return nil, err } - return &pb.NewChainWriterReply{ChainWriterID: id}, nil + return &pb.NewContractWriterReply{ContractWriterID: id}, nil } func (r *relayerServer) NewContractReader(ctx context.Context, request *pb.NewContractReaderRequest) (*pb.NewContractReaderReply, error) { diff --git a/pkg/loop/internal/relayer/test/relayer.go b/pkg/loop/internal/relayer/test/relayer.go index f226284a1..dd04ab902 100644 --- a/pkg/loop/internal/relayer/test/relayer.go +++ b/pkg/loop/internal/relayer/test/relayer.go @@ -135,7 +135,7 @@ func (s staticPluginRelayer) Name() string { panic("unimplemented") } func (s staticPluginRelayer) HealthReport() map[string]error { panic("unimplemented") } -func (s staticPluginRelayer) NewChainWriter(_ context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { +func (s staticPluginRelayer) NewContractWriter(_ context.Context, _ []byte) (types.ContractWriter, error) { return nil, errors.New("not implemented") } diff --git a/pkg/loop/internal/relayerset/client.go b/pkg/loop/internal/relayerset/client.go index 5dc4524b3..b9909f024 100644 --- a/pkg/loop/internal/relayerset/client.go +++ b/pkg/loop/internal/relayerset/client.go @@ -152,14 +152,14 @@ func (k *Client) NewContractReader(ctx context.Context, relayID types.RelayID, c return resp.ContractReaderId, nil } -func (k *Client) NewChainWriter(ctx context.Context, relayID types.RelayID, chainWriterConfig []byte) (uint32, error) { - req := &relayerset.NewChainWriterRequest{ - RelayerId: &relayerset.RelayerId{ChainId: relayID.ChainID, Network: relayID.Network}, - ChainWriterConfig: chainWriterConfig, +func (k *Client) NewContractWriter(ctx context.Context, relayID types.RelayID, contractWriterConfig []byte) (uint32, error) { + req := &relayerset.NewContractWriterRequest{ + RelayerId: &relayerset.RelayerId{ChainId: relayID.ChainID, Network: relayID.Network}, + ContractWriterConfig: contractWriterConfig, } - resp, err := k.relayerSetClient.NewChainWriter(ctx, req) + resp, err := k.relayerSetClient.NewContractWriter(ctx, req) if err != nil { - return 0, fmt.Errorf("error getting new chain writer: %w", err) + return 0, fmt.Errorf("error getting new contract writer: %w", err) } - return resp.ChainWriterId, nil + return resp.ContractWriterId, nil } diff --git a/pkg/loop/internal/relayerset/relayer.go b/pkg/loop/internal/relayerset/relayer.go index fe0cd4351..e42d09e7f 100644 --- a/pkg/loop/internal/relayerset/relayer.go +++ b/pkg/loop/internal/relayerset/relayer.go @@ -7,8 +7,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/net" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer" - "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainwriter" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractreader" + "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractwriter" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/core" ) @@ -49,15 +49,15 @@ func (r *relayerClient) NewContractReader(_ context.Context, contractReaderConfi return contractreader.NewClient(r.relayerSetClient.BrokerExt.WithName("ContractReaderClientInRelayerSet"), cc), nil } -func (r *relayerClient) NewChainWriter(_ context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { - cwc := r.relayerSetClient.NewClientConn("ChainWriter", func(ctx context.Context) (uint32, net.Resources, error) { - chainWriterID, err := r.relayerSetClient.NewChainWriter(ctx, r.relayerID, chainWriterConfig) +func (r *relayerClient) NewContractWriter(_ context.Context, contractWriterConfig []byte) (types.ContractWriter, error) { + cwc := r.relayerSetClient.NewClientConn("ContractWriter", func(ctx context.Context) (uint32, net.Resources, error) { + contractWriterID, err := r.relayerSetClient.NewContractWriter(ctx, r.relayerID, contractWriterConfig) if err != nil { return 0, nil, err } - return chainWriterID, nil, nil + return contractWriterID, nil, nil }) - return chainwriter.NewClient(r.relayerSetClient.BrokerExt.WithName("ChainWriterClient"), cwc), nil + return contractwriter.NewClient(r.relayerSetClient.BrokerExt.WithName("ContractWriterClient"), cwc), nil } func (r *relayerClient) Start(ctx context.Context) error { diff --git a/pkg/loop/internal/relayerset/server.go b/pkg/loop/internal/relayerset/server.go index 8e809f1f8..a3fa55ec9 100644 --- a/pkg/loop/internal/relayerset/server.go +++ b/pkg/loop/internal/relayerset/server.go @@ -13,8 +13,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/net" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb/relayerset" - "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainwriter" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractreader" + "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/contractwriter" "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayerset/inprocessprovider" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/core" @@ -139,15 +139,15 @@ func (s *Server) NewPluginProvider(ctx context.Context, req *relayerset.NewPlugi return &relayerset.NewPluginProviderResponse{PluginProviderId: providerID}, nil } -// RelayerSet is supposed to serve relayers, which then hold a ContractReader and ChainWriter. Serving NewContractReader -// and NewChainWriter from RelayerSet is a way to save us from instantiating an extra server for the Relayer. Without +// RelayerSet is supposed to serve relayers, which then hold a ContractReader and ContractWriter. Serving NewContractReader +// and NewContractWriter from RelayerSet is a way to save us from instantiating an extra server for the Relayer. Without // this approach, the calls we would make normally are // - RelayerSet.Get -> Relayer // - Relayer.NewContractReader -> ContractReader // // We could translate this to the GRPC world by having each call to RelayerSet.Get wrap the returned relayer in a server // and register that to the GRPC server. However this is actually pretty inefficient since a relayer object on its own -// is not useful. Users will always want to use the relayer to instantiate a contractreader or chainwriter. So we can avoid +// is not useful. Users will always want to use the relayer to instantiate a contractreader or contractwriter. So we can avoid // the intermediate server for the relayer by just storing a reference to the relayerSet client and the relayer we want // to fetch. I.e. the calls described above instead would become: // - RelayerSet.Get -> (RelayerSetClient, RelayerID). Effectively this call just acts as check that Relayer exists @@ -182,47 +182,47 @@ func (s *Server) NewContractReader(ctx context.Context, req *relayerset.NewContr return &relayerset.NewContractReaderResponse{ContractReaderId: id}, nil } -// RelayerSet is supposed to serve relayers, which then hold a ContractReader and ChainWriter. Serving NewChainWriter -// and NewChainWriter from RelayerSet is a way to save us from instantiating an extra server for the Relayer. Without +// RelayerSet is supposed to serve relayers, which then hold a ContractReader and ContractWriter. Serving NewContractWriter +// and NewContractWriter from RelayerSet is a way to save us from instantiating an extra server for the Relayer. Without // this approach, the calls we would make normally are // - RelayerSet.Get -> Relayer -// - Relayer.NewChainWriter -> ChainWriter +// - Relayer.NewContractWriter -> ContractWriter // // We could translate this to the GRPC world by having each call to RelayerSet.Get wrap the returned relayer in a server // and register that to the GRPC server. However this is actually pretty inefficient since a relayer object on its own -// is not useful. Users will always want to use the relayer to instantiate a contractreader or chainwriter. So we can avoid +// is not useful. Users will always want to use the relayer to instantiate a contractreader or contractwriter. So we can avoid // the intermediate server for the relayer by just storing a reference to the relayerSet client and the relayer we want // to fetch. I.e. the calls described above instead would become: // - RelayerSet.Get -> (RelayerSetClient, RelayerID). Effectively this call just acts as check that Relayer exists // -// RelayerClient.NewChainWriter -> This is a call to RelayerSet.NewChainWriter with (relayerID, []contractReaderConfig); -// The implementation will then fetch the relayer and call NewChainWriter on it -func (s *Server) NewChainWriter(ctx context.Context, req *relayerset.NewChainWriterRequest) (*relayerset.NewChainWriterResponse, error) { +// RelayerClient.NewContractWriter -> This is a call to RelayerSet.NewContractWriter with (relayerID, []contractWriterConfig); +// The implementation will then fetch the relayer and call NewContractWriter on it +func (s *Server) NewContractWriter(ctx context.Context, req *relayerset.NewContractWriterRequest) (*relayerset.NewContractWriterResponse, error) { relayer, err := s.getRelayer(ctx, req.RelayerId) if err != nil { return nil, err } - chainWriter, err := relayer.NewChainWriter(ctx, req.ChainWriterConfig) + contractWriter, err := relayer.NewContractWriter(ctx, req.ContractWriterConfig) if err != nil { return nil, status.Errorf(codes.Internal, "error creating contract reader: %v", err) } - // Start ChainWriter service - if err = chainWriter.Start(ctx); err != nil { + // Start ContractWriter service + if err = contractWriter.Start(ctx); err != nil { return nil, err } - // Start gRPC service for the ChainWriter service above - const name = "ChainWriterInRelayerSet" + // Start gRPC service for the ContractWriter service above + const name = "ContractWriterInRelayerSet" id, _, err := s.broker.ServeNew(name, func(s *grpc.Server) { - chainwriter.RegisterChainWriterService(s, chainWriter) - }, net.Resource{Closer: chainWriter, Name: name}) + contractwriter.RegisterContractWriterService(s, contractWriter) + }, net.Resource{Closer: contractWriter, Name: name}) if err != nil { return nil, err } - return &relayerset.NewChainWriterResponse{ChainWriterId: id}, nil + return &relayerset.NewContractWriterResponse{ContractWriterId: id}, nil } // getProviderConnection wraps a non-LOOPP provider in an in process provider server. This can be removed once all providers are LOOPP providers. diff --git a/pkg/loop/internal/types/types.go b/pkg/loop/internal/types/types.go index 9e3f50e39..30f8a73fa 100644 --- a/pkg/loop/internal/types/types.go +++ b/pkg/loop/internal/types/types.go @@ -45,9 +45,9 @@ type OCR3CapabilityProvider interface { type Relayer interface { types.ChainService - // NewChainWriter returns a new ChainWriter. + // NewContractWriter returns a new ContractWriter. // The format of config depends on the implementation. - NewChainWriter(ctx context.Context, chainWriterConfig []byte) (types.ChainWriter, error) + NewContractWriter(ctx context.Context, contractWriterConfig []byte) (types.ContractWriter, error) // NewContractReader returns a new ContractReader. // The format of contractReaderConfig depends on the implementation. diff --git a/pkg/loop/mocks/relayer.go b/pkg/loop/mocks/relayer.go index 097546a0d..10ef5e3d6 100644 --- a/pkg/loop/mocks/relayer.go +++ b/pkg/loop/mocks/relayer.go @@ -347,65 +347,6 @@ func (_c *Relayer_Name_Call) RunAndReturn(run func() string) *Relayer_Name_Call return _c } -// NewChainWriter provides a mock function with given fields: ctx, chainWriterConfig -func (_m *Relayer) NewChainWriter(ctx context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { - ret := _m.Called(ctx, chainWriterConfig) - - if len(ret) == 0 { - panic("no return value specified for NewChainWriter") - } - - var r0 types.ChainWriter - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ChainWriter, error)); ok { - return rf(ctx, chainWriterConfig) - } - if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ChainWriter); ok { - r0 = rf(ctx, chainWriterConfig) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.ChainWriter) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok { - r1 = rf(ctx, chainWriterConfig) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Relayer_NewChainWriter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewChainWriter' -type Relayer_NewChainWriter_Call struct { - *mock.Call -} - -// NewChainWriter is a helper method to define mock.On call -// - ctx context.Context -// - chainWriterConfig []byte -func (_e *Relayer_Expecter) NewChainWriter(ctx interface{}, chainWriterConfig interface{}) *Relayer_NewChainWriter_Call { - return &Relayer_NewChainWriter_Call{Call: _e.mock.On("NewChainWriter", ctx, chainWriterConfig)} -} - -func (_c *Relayer_NewChainWriter_Call) Run(run func(ctx context.Context, chainWriterConfig []byte)) *Relayer_NewChainWriter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]byte)) - }) - return _c -} - -func (_c *Relayer_NewChainWriter_Call) Return(_a0 types.ChainWriter, _a1 error) *Relayer_NewChainWriter_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *Relayer_NewChainWriter_Call) RunAndReturn(run func(context.Context, []byte) (types.ChainWriter, error)) *Relayer_NewChainWriter_Call { - _c.Call.Return(run) - return _c -} - // NewConfigProvider provides a mock function with given fields: _a0, _a1 func (_m *Relayer) NewConfigProvider(_a0 context.Context, _a1 types.RelayArgs) (types.ConfigProvider, error) { ret := _m.Called(_a0, _a1) @@ -524,6 +465,65 @@ func (_c *Relayer_NewContractReader_Call) RunAndReturn(run func(context.Context, return _c } +// NewContractWriter provides a mock function with given fields: ctx, contractWriterConfig +func (_m *Relayer) NewContractWriter(ctx context.Context, contractWriterConfig []byte) (types.ContractWriter, error) { + ret := _m.Called(ctx, contractWriterConfig) + + if len(ret) == 0 { + panic("no return value specified for NewContractWriter") + } + + var r0 types.ContractWriter + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ContractWriter, error)); ok { + return rf(ctx, contractWriterConfig) + } + if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ContractWriter); ok { + r0 = rf(ctx, contractWriterConfig) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.ContractWriter) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok { + r1 = rf(ctx, contractWriterConfig) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Relayer_NewContractWriter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewContractWriter' +type Relayer_NewContractWriter_Call struct { + *mock.Call +} + +// NewContractWriter is a helper method to define mock.On call +// - ctx context.Context +// - contractWriterConfig []byte +func (_e *Relayer_Expecter) NewContractWriter(ctx interface{}, contractWriterConfig interface{}) *Relayer_NewContractWriter_Call { + return &Relayer_NewContractWriter_Call{Call: _e.mock.On("NewContractWriter", ctx, contractWriterConfig)} +} + +func (_c *Relayer_NewContractWriter_Call) Run(run func(ctx context.Context, contractWriterConfig []byte)) *Relayer_NewContractWriter_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([]byte)) + }) + return _c +} + +func (_c *Relayer_NewContractWriter_Call) Return(_a0 types.ContractWriter, _a1 error) *Relayer_NewContractWriter_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Relayer_NewContractWriter_Call) RunAndReturn(run func(context.Context, []byte) (types.ContractWriter, error)) *Relayer_NewContractWriter_Call { + _c.Call.Return(run) + return _c +} + // NewLLOProvider provides a mock function with given fields: _a0, _a1, _a2 func (_m *Relayer) NewLLOProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.LLOProvider, error) { ret := _m.Called(_a0, _a1, _a2) diff --git a/pkg/loop/relayer_service.go b/pkg/loop/relayer_service.go index c076d61d0..7420854fa 100644 --- a/pkg/loop/relayer_service.go +++ b/pkg/loop/relayer_service.go @@ -48,11 +48,11 @@ func (r *RelayerService) NewContractReader(ctx context.Context, contractReaderCo return r.Service.NewContractReader(ctx, contractReaderConfig) } -func (r *RelayerService) NewChainWriter(ctx context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { +func (r *RelayerService) NewContractWriter(ctx context.Context, contractWriterConfig []byte) (types.ContractWriter, error) { if err := r.WaitCtx(ctx); err != nil { return nil, err } - return r.Service.NewChainWriter(ctx, chainWriterConfig) + return r.Service.NewContractWriter(ctx, contractWriterConfig) } func (r *RelayerService) NewConfigProvider(ctx context.Context, args types.RelayArgs) (types.ConfigProvider, error) { diff --git a/pkg/loop/server.go b/pkg/loop/server.go index e480566cf..c866be20b 100644 --- a/pkg/loop/server.go +++ b/pkg/loop/server.go @@ -104,6 +104,9 @@ func (s *Server) start() error { } if tracingConfig.Enabled { + if beholderCfg.AuthHeaders != nil { + tracingConfig.AuthHeaders = beholderCfg.AuthHeaders + } exporter, err := tracingConfig.NewSpanExporter() if err != nil { return fmt.Errorf("failed to setup tracing exporter: %w", err) diff --git a/pkg/loop/telem.go b/pkg/loop/telem.go index 4d80d496b..c66949b23 100644 --- a/pkg/loop/telem.go +++ b/pkg/loop/telem.go @@ -53,6 +53,9 @@ type TracingConfig struct { // OnDialError is called when the dialer fails, providing an opportunity to log. OnDialError func(error) + + // Auth + AuthHeaders map[string]string } // NewGRPCOpts initializes open telemetry and returns GRPCOpts with telemetry interceptors. @@ -150,7 +153,10 @@ func (config TracingConfig) NewSpanExporter() (sdktrace.SpanExporter, error) { return nil, err } - traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithGRPCConn(conn)) + traceExporter, err := otlptracegrpc.New(ctx, + otlptracegrpc.WithGRPCConn(conn), + otlptracegrpc.WithHeaders(config.AuthHeaders), + ) if err != nil { return nil, err } diff --git a/pkg/loop/testutils/utils.go b/pkg/loop/testutils/utils.go index 8df3cce6d..555255f5b 100644 --- a/pkg/loop/testutils/utils.go +++ b/pkg/loop/testutils/utils.go @@ -11,7 +11,7 @@ import ( // the duplication of the function is required so that the test of the LOOP servers themselves // can dog food the same testers without creating a circular dependency. -// WrapContractReaderTesterForLoop allows you to test a [types.ContractReader] and [types.ChainWriter] implementation behind a LOOP server +// WrapContractReaderTesterForLoop allows you to test a [types.ContractReader] and [types.ContractWriter] implementation behind a LOOP server func WrapContractReaderTesterForLoop(wrapped interfacetests.ChainComponentsInterfaceTester[*testing.T]) interfacetests.ChainComponentsInterfaceTester[*testing.T] { return test.WrapContractReaderTesterForLoop(wrapped) } diff --git a/pkg/services/health.go b/pkg/services/health.go index 7bdfb5113..7108e53b6 100644 --- a/pkg/services/health.go +++ b/pkg/services/health.go @@ -257,3 +257,14 @@ func (c *HealthChecker) IsHealthy() (healthy bool, errors map[string]error) { return } + +// ContainsError - returns true if report contains targetErr +func ContainsError(report map[string]error, targetErr error) bool { + for _, err := range report { + if errors.Is(err, targetErr) { + return true + } + } + + return false +} diff --git a/pkg/services/health_test.go b/pkg/services/health_test.go new file mode 100644 index 000000000..325d2cf20 --- /dev/null +++ b/pkg/services/health_test.go @@ -0,0 +1,58 @@ +package services + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestContainsError(t *testing.T) { + anError := errors.New("an error") + anotherError := errors.New("another error") + testCases := []struct { + Name string + Report map[string]error + Target error + ExpectedResult bool + }{ + { + Name: "nil map", + Report: nil, + Target: anError, + ExpectedResult: false, + }, + { + Name: "report contains service, but it's healthy", + Report: map[string]error{"service": nil}, + Target: anError, + ExpectedResult: false, + }, + { + Name: "service is not healthy, but it's not caused by target error", + Report: map[string]error{"service": anotherError}, + Target: anError, + ExpectedResult: false, + }, + { + Name: "service is not healthy and contains wrapper target", + Report: map[string]error{"service": fmt.Errorf("wrapped error: %w", anError)}, + Target: anError, + ExpectedResult: true, + }, + { + Name: "service is not healthy due to multiple errors including target", + Report: map[string]error{"service": errors.Join(anError, anotherError)}, + Target: anError, + ExpectedResult: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + actualResult := ContainsError(tc.Report, tc.Target) + assert.Equal(t, tc.ExpectedResult, actualResult) + }) + } +} diff --git a/pkg/services/servicetest/run.go b/pkg/services/servicetest/run.go index 8a1046e3c..70ab607f1 100644 --- a/pkg/services/servicetest/run.go +++ b/pkg/services/servicetest/run.go @@ -28,7 +28,10 @@ type TestingT interface { func Run[R Runnable](tb TestingT, r R) R { tb.Helper() require.NoError(tb, r.Start(tests.Context(tb)), "service failed to start") - tb.Cleanup(func() { assert.NoError(tb, r.Close(), "error closing service") }) + tb.Cleanup(func() { + tb.Helper() + assert.NoError(tb, r.Close(), "error closing service") + }) return r } diff --git a/pkg/sqlutil/sqltest/data_source.go b/pkg/sqlutil/sqltest/data_source.go new file mode 100644 index 000000000..32413e52c --- /dev/null +++ b/pkg/sqlutil/sqltest/data_source.go @@ -0,0 +1,65 @@ +package sqltest + +import ( + "context" + "database/sql" + + "github.com/jmoiron/sqlx" + + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" +) + +// NewNoOpDataSource returns an empty DataSource type which will satisfy the interface +func NewNoOpDataSource() sqlutil.DataSource { + return &noOpDataSource{} +} + +type noOpDataSource struct{} + +func (ds *noOpDataSource) BindNamed(s string, _ interface{}) (string, []interface{}, error) { + return "", nil, nil +} + +func (ds *noOpDataSource) DriverName() string { + return "" +} + +func (ds *noOpDataSource) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { + return nil, nil +} + +func (ds *noOpDataSource) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { + return nil +} + +func (ds *noOpDataSource) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) { + return nil, nil +} + +func (ds *noOpDataSource) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) { + return nil, nil +} + +func (_m *noOpDataSource) PrepareNamedContext(ctx context.Context, query string) (*sqlx.NamedStmt, error) { + return nil, nil +} + +func (ds *noOpDataSource) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { + return nil, nil +} + +func (ds *noOpDataSource) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *sqlx.Row { + return nil +} + +func (ds *noOpDataSource) QueryxContext(ctx context.Context, query string, args ...interface{}) (*sqlx.Rows, error) { + return nil, nil +} + +func (ds *noOpDataSource) Rebind(s string) string { + return "" +} + +func (ds *noOpDataSource) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { + return nil +} diff --git a/pkg/types/codec.go b/pkg/types/codec.go index 395610911..8b17209b9 100644 --- a/pkg/types/codec.go +++ b/pkg/types/codec.go @@ -31,7 +31,7 @@ type Decoder interface { /* Codec is an interface that provides encoding and decoding functionality for a specific type identified by a name. -Because there are many types that a [ContractReader] or [ChainWriter] can either accept or return, all encoding +Because there are many types that a [ContractReader] or [ContractWriter] can either accept or return, all encoding instructions provided by the codec are based on the type name. Starting from the lowest level, take for instance a [big.Int] encoder where we want the output to be big endian binary diff --git a/pkg/types/contract_reader.go b/pkg/types/contract_reader.go index 9cf6b0555..5d317de77 100644 --- a/pkg/types/contract_reader.go +++ b/pkg/types/contract_reader.go @@ -2,6 +2,7 @@ package types import ( "context" + "iter" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types/query" @@ -15,6 +16,7 @@ const ( ErrContractReaderConfigMissing = UnimplementedError("ContractReader entry missing from RelayConfig") ErrInternal = InternalError("internal error") ErrNotFound = NotFoundError("not found") + ErrFinalityViolated = InternalError("finality violated") ) // ContractReader defines essential read operations a chain should implement for reading contract values and events. @@ -65,9 +67,26 @@ type ContractReader interface { // QueryKey provides fetching chain agnostic events (Sequence) with general querying capability. QueryKey(ctx context.Context, contract BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]Sequence, error) + // QueryKeys provides fetching chain agnostic events (Sequence) of different types with general querying capability. + // The iterator returns a pair of key and sequence. + QueryKeys(ctx context.Context, filters []ContractKeyFilter, limitAndSort query.LimitAndSort) (iter.Seq2[string, Sequence], error) + + // HealthReport returns a full health report of the callee including its dependencies. + // Keys are based on Name(), with nil values when healthy or errors otherwise. + // Use CopyHealth to collect reports from sub-services. + // This should run very fast, so avoid doing computation and instead prefer reporting pre-calculated state. + // On finality violation report must contain at least one ErrFinalityViolation. + HealthReport() map[string]error + mustEmbedUnimplementedContractReader() } +type ContractKeyFilter struct { + query.KeyFilter + Contract BoundContract + SequenceDataType any +} + // BatchGetLatestValuesRequest string is contract name. type BatchGetLatestValuesRequest map[BoundContract]ContractBatch type ContractBatch []BatchRead @@ -153,6 +172,10 @@ func (UnimplementedContractReader) QueryKey(ctx context.Context, boundContract B return nil, UnimplementedError("ContractReader.QueryKey unimplemented") } +func (UnimplementedContractReader) QueryKeys(ctx context.Context, keyQueries []ContractKeyFilter, limitAndSort query.LimitAndSort) (iter.Seq2[string, Sequence], error) { + return nil, UnimplementedError("ContractReader.QueryKeys unimplemented") +} + func (UnimplementedContractReader) Start(context.Context) error { return UnimplementedError("ContractReader.Start unimplemented") } diff --git a/pkg/types/chain_writer.go b/pkg/types/contract_writer.go similarity index 91% rename from pkg/types/chain_writer.go rename to pkg/types/contract_writer.go index 28b243546..f556fcb66 100644 --- a/pkg/types/chain_writer.go +++ b/pkg/types/contract_writer.go @@ -11,10 +11,10 @@ const ( ErrSettingTransactionGasLimitNotSupported = InvalidArgumentError("setting transaction gas limit is not supported") ) -type ChainWriter interface { +type ContractWriter interface { services.Service - // SubmitTransaction packs and broadcasts a transaction to the underlying chain. + // SubmitTransaction packs and broadcasts a transaction to the underlying chain contract. // // - `args` should be any object which maps a set of method param into the contract and method specific method params. // - `transactionID` will be used by the underlying TXM as an idempotency key, and unique reference to track transaction attempts. @@ -31,8 +31,8 @@ type ChainWriter interface { type TxMeta struct { // Used for Keystone Workflows WorkflowExecutionID *string - // An optional maximum gas limit for the transaction. If not set the ChainWriter implementation will be responsible for - // setting a gas limit for the transaction. If it is set and the ChainWriter implementation does not support setting + // An optional maximum gas limit for the transaction. If not set the ContractWriter implementation will be responsible for + // setting a gas limit for the transaction. If it is set and the ContractWriter implementation does not support setting // this value per transaction it will return ErrSettingTransactionGasLimitNotSupported GasLimit *big.Int } diff --git a/pkg/types/core/capabilities_registry.go b/pkg/types/core/capabilities_registry.go index 0f139b066..e520cd8bc 100644 --- a/pkg/types/core/capabilities_registry.go +++ b/pkg/types/core/capabilities_registry.go @@ -17,4 +17,5 @@ type CapabilitiesRegistry interface { GetTarget(ctx context.Context, ID string) (capabilities.TargetCapability, error) List(ctx context.Context) ([]capabilities.BaseCapability, error) Add(ctx context.Context, c capabilities.BaseCapability) error + Remove(ctx context.Context, ID string) error } diff --git a/pkg/types/core/mocks/capabilities_registry.go b/pkg/types/core/mocks/capabilities_registry.go index 105b414af..aa0a3bce7 100644 --- a/pkg/types/core/mocks/capabilities_registry.go +++ b/pkg/types/core/mocks/capabilities_registry.go @@ -537,6 +537,53 @@ func (_c *CapabilitiesRegistry_LocalNode_Call) RunAndReturn(run func(context.Con return _c } +// Remove provides a mock function with given fields: ctx, ID +func (_m *CapabilitiesRegistry) Remove(ctx context.Context, ID string) error { + ret := _m.Called(ctx, ID) + + if len(ret) == 0 { + panic("no return value specified for Remove") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, ID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CapabilitiesRegistry_Remove_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Remove' +type CapabilitiesRegistry_Remove_Call struct { + *mock.Call +} + +// Remove is a helper method to define mock.On call +// - ctx context.Context +// - ID string +func (_e *CapabilitiesRegistry_Expecter) Remove(ctx interface{}, ID interface{}) *CapabilitiesRegistry_Remove_Call { + return &CapabilitiesRegistry_Remove_Call{Call: _e.mock.On("Remove", ctx, ID)} +} + +func (_c *CapabilitiesRegistry_Remove_Call) Run(run func(ctx context.Context, ID string)) *CapabilitiesRegistry_Remove_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *CapabilitiesRegistry_Remove_Call) Return(_a0 error) *CapabilitiesRegistry_Remove_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *CapabilitiesRegistry_Remove_Call) RunAndReturn(run func(context.Context, string) error) *CapabilitiesRegistry_Remove_Call { + _c.Call.Return(run) + return _c +} + // NewCapabilitiesRegistry creates a new instance of CapabilitiesRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCapabilitiesRegistry(t interface { diff --git a/pkg/types/core/mocks/relayer.go b/pkg/types/core/mocks/relayer.go index f8dfc59a8..1b14433ae 100644 --- a/pkg/types/core/mocks/relayer.go +++ b/pkg/types/core/mocks/relayer.go @@ -217,29 +217,29 @@ func (_c *Relayer_Name_Call) RunAndReturn(run func() string) *Relayer_Name_Call return _c } -// NewChainWriter provides a mock function with given fields: _a0, chainWriterConfig -func (_m *Relayer) NewChainWriter(_a0 context.Context, chainWriterConfig []byte) (types.ChainWriter, error) { - ret := _m.Called(_a0, chainWriterConfig) +// NewContractReader provides a mock function with given fields: _a0, contractReaderConfig +func (_m *Relayer) NewContractReader(_a0 context.Context, contractReaderConfig []byte) (types.ContractReader, error) { + ret := _m.Called(_a0, contractReaderConfig) if len(ret) == 0 { - panic("no return value specified for NewChainWriter") + panic("no return value specified for NewContractReader") } - var r0 types.ChainWriter + var r0 types.ContractReader var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ChainWriter, error)); ok { - return rf(_a0, chainWriterConfig) + if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ContractReader, error)); ok { + return rf(_a0, contractReaderConfig) } - if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ChainWriter); ok { - r0 = rf(_a0, chainWriterConfig) + if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ContractReader); ok { + r0 = rf(_a0, contractReaderConfig) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(types.ChainWriter) + r0 = ret.Get(0).(types.ContractReader) } } if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok { - r1 = rf(_a0, chainWriterConfig) + r1 = rf(_a0, contractReaderConfig) } else { r1 = ret.Error(1) } @@ -247,58 +247,58 @@ func (_m *Relayer) NewChainWriter(_a0 context.Context, chainWriterConfig []byte) return r0, r1 } -// Relayer_NewChainWriter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewChainWriter' -type Relayer_NewChainWriter_Call struct { +// Relayer_NewContractReader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewContractReader' +type Relayer_NewContractReader_Call struct { *mock.Call } -// NewChainWriter is a helper method to define mock.On call +// NewContractReader is a helper method to define mock.On call // - _a0 context.Context -// - chainWriterConfig []byte -func (_e *Relayer_Expecter) NewChainWriter(_a0 interface{}, chainWriterConfig interface{}) *Relayer_NewChainWriter_Call { - return &Relayer_NewChainWriter_Call{Call: _e.mock.On("NewChainWriter", _a0, chainWriterConfig)} +// - contractReaderConfig []byte +func (_e *Relayer_Expecter) NewContractReader(_a0 interface{}, contractReaderConfig interface{}) *Relayer_NewContractReader_Call { + return &Relayer_NewContractReader_Call{Call: _e.mock.On("NewContractReader", _a0, contractReaderConfig)} } -func (_c *Relayer_NewChainWriter_Call) Run(run func(_a0 context.Context, chainWriterConfig []byte)) *Relayer_NewChainWriter_Call { +func (_c *Relayer_NewContractReader_Call) Run(run func(_a0 context.Context, contractReaderConfig []byte)) *Relayer_NewContractReader_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].([]byte)) }) return _c } -func (_c *Relayer_NewChainWriter_Call) Return(_a0 types.ChainWriter, _a1 error) *Relayer_NewChainWriter_Call { +func (_c *Relayer_NewContractReader_Call) Return(_a0 types.ContractReader, _a1 error) *Relayer_NewContractReader_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *Relayer_NewChainWriter_Call) RunAndReturn(run func(context.Context, []byte) (types.ChainWriter, error)) *Relayer_NewChainWriter_Call { +func (_c *Relayer_NewContractReader_Call) RunAndReturn(run func(context.Context, []byte) (types.ContractReader, error)) *Relayer_NewContractReader_Call { _c.Call.Return(run) return _c } -// NewContractReader provides a mock function with given fields: _a0, contractReaderConfig -func (_m *Relayer) NewContractReader(_a0 context.Context, contractReaderConfig []byte) (types.ContractReader, error) { - ret := _m.Called(_a0, contractReaderConfig) +// NewContractWriter provides a mock function with given fields: _a0, contractWriterConfig +func (_m *Relayer) NewContractWriter(_a0 context.Context, contractWriterConfig []byte) (types.ContractWriter, error) { + ret := _m.Called(_a0, contractWriterConfig) if len(ret) == 0 { - panic("no return value specified for NewContractReader") + panic("no return value specified for NewContractWriter") } - var r0 types.ContractReader + var r0 types.ContractWriter var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ContractReader, error)); ok { - return rf(_a0, contractReaderConfig) + if rf, ok := ret.Get(0).(func(context.Context, []byte) (types.ContractWriter, error)); ok { + return rf(_a0, contractWriterConfig) } - if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ContractReader); ok { - r0 = rf(_a0, contractReaderConfig) + if rf, ok := ret.Get(0).(func(context.Context, []byte) types.ContractWriter); ok { + r0 = rf(_a0, contractWriterConfig) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(types.ContractReader) + r0 = ret.Get(0).(types.ContractWriter) } } if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok { - r1 = rf(_a0, contractReaderConfig) + r1 = rf(_a0, contractWriterConfig) } else { r1 = ret.Error(1) } @@ -306,31 +306,31 @@ func (_m *Relayer) NewContractReader(_a0 context.Context, contractReaderConfig [ return r0, r1 } -// Relayer_NewContractReader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewContractReader' -type Relayer_NewContractReader_Call struct { +// Relayer_NewContractWriter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewContractWriter' +type Relayer_NewContractWriter_Call struct { *mock.Call } -// NewContractReader is a helper method to define mock.On call +// NewContractWriter is a helper method to define mock.On call // - _a0 context.Context -// - contractReaderConfig []byte -func (_e *Relayer_Expecter) NewContractReader(_a0 interface{}, contractReaderConfig interface{}) *Relayer_NewContractReader_Call { - return &Relayer_NewContractReader_Call{Call: _e.mock.On("NewContractReader", _a0, contractReaderConfig)} +// - contractWriterConfig []byte +func (_e *Relayer_Expecter) NewContractWriter(_a0 interface{}, contractWriterConfig interface{}) *Relayer_NewContractWriter_Call { + return &Relayer_NewContractWriter_Call{Call: _e.mock.On("NewContractWriter", _a0, contractWriterConfig)} } -func (_c *Relayer_NewContractReader_Call) Run(run func(_a0 context.Context, contractReaderConfig []byte)) *Relayer_NewContractReader_Call { +func (_c *Relayer_NewContractWriter_Call) Run(run func(_a0 context.Context, contractWriterConfig []byte)) *Relayer_NewContractWriter_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].([]byte)) }) return _c } -func (_c *Relayer_NewContractReader_Call) Return(_a0 types.ContractReader, _a1 error) *Relayer_NewContractReader_Call { +func (_c *Relayer_NewContractWriter_Call) Return(_a0 types.ContractWriter, _a1 error) *Relayer_NewContractWriter_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *Relayer_NewContractReader_Call) RunAndReturn(run func(context.Context, []byte) (types.ContractReader, error)) *Relayer_NewContractReader_Call { +func (_c *Relayer_NewContractWriter_Call) RunAndReturn(run func(context.Context, []byte) (types.ContractWriter, error)) *Relayer_NewContractWriter_Call { _c.Call.Return(run) return _c } diff --git a/pkg/types/core/relayerset.go b/pkg/types/core/relayerset.go index bb1b84d45..3cc92ff39 100644 --- a/pkg/types/core/relayerset.go +++ b/pkg/types/core/relayerset.go @@ -31,6 +31,6 @@ type Relayer interface { services.Service NewPluginProvider(context.Context, RelayArgs, PluginArgs) (types.PluginProvider, error) NewContractReader(_ context.Context, contractReaderConfig []byte) (types.ContractReader, error) - NewChainWriter(_ context.Context, chainWriterConfig []byte) (types.ChainWriter, error) + NewContractWriter(_ context.Context, contractWriterConfig []byte) (types.ContractWriter, error) LatestHead(context.Context) (types.Head, error) } diff --git a/pkg/types/interfacetests/chain_components_interface_tests.go b/pkg/types/interfacetests/chain_components_interface_tests.go index 70721934c..7d32471ce 100644 --- a/pkg/types/interfacetests/chain_components_interface_tests.go +++ b/pkg/types/interfacetests/chain_components_interface_tests.go @@ -59,18 +59,28 @@ const ( ContractReaderQueryKeyCanLimitResultsWithCursor = "QueryKey can limit results with cursor" ) +// Query keys +const ( + ContractReaderQueryKeysReturnsDataTwoEventTypes = "QueryKeys returns sequence data properly for two event types" + ContractReaderQueryKeysNotFound = "QueryKeys returns not found if sequence never happened" + ContractReaderQueryKeysReturnsData = "QueryKeys returns sequence data properly" + ContractReaderQueryKeysReturnsDataAsValuesDotValue = "QueryKeys returns sequence data properly as values.Value" + ContractReaderQueryKeysCanFilterWithValueComparator = "QueryKeys can filter data with value comparator" + ContractReaderQueryKeysCanLimitResultsWithCursor = "QueryKeys can limit results with cursor" +) + type ChainComponentsInterfaceTester[T TestingT[T]] interface { BasicTester[T] GetContractReader(t T) types.ContractReader - GetChainWriter(t T) types.ChainWriter + GetContractWriter(t T) types.ContractWriter GetBindings(t T) []types.BoundContract // DirtyContracts signals to the underlying tester than the test contracts are dirty, i.e. the state has been changed such that // new, fresh contracts should be deployed. This usually happens after a value is written to the contract via - // the ChainWriter. + // the ContractWriter. DirtyContracts() MaxWaitTimeForEvents() time.Duration // GenerateBlocksTillConfidenceLevel is only used by the internal common tests, all other tests can/should - // rely on the ChainWriter waiting for actual blocks to be mined. + // rely on the ContractWriter waiting for actual blocks to be mined. GenerateBlocksTillConfidenceLevel(t T, contractName, readName string, confidenceLevel primitives.ConfidenceLevel) } @@ -85,6 +95,8 @@ const ( MethodSettingStruct = "addTestStruct" MethodSettingUint64 = "setAlterablePrimitiveValue" MethodTriggeringEvent = "triggerEvent" + MethodTriggeringEventWithDynamicTopic = "triggerEventWithDynamicTopic" + DynamicTopicEventName = "TriggeredEventWithDynamicTopic" EventName = "SomeEvent" EventNameField = EventName + ".Field" ProtoTest = "ProtoTest" @@ -100,13 +112,340 @@ var AnySliceToReadWithoutAnArgument = []uint64{3, 4} const AnyExtraValue = 3 func RunContractReaderInterfaceTests[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], mockRun bool) { - t.Run("GetLatestValue for "+tester.Name(), func(t T) { runContractReaderGetLatestValueInterfaceTests(t, tester, mockRun) }) - t.Run("BatchGetLatestValues for "+tester.Name(), func(t T) { runContractReaderBatchGetLatestValuesInterfaceTests(t, tester, mockRun) }) - t.Run("QueryKey for "+tester.Name(), func(t T) { runQueryKeyInterfaceTests(t, tester) }) + t.Run(tester.Name(), func(t T) { + t.Run("GetLatestValue", func(t T) { runContractReaderGetLatestValueInterfaceTests(t, tester, mockRun) }) + t.Run("BatchGetLatestValues", func(t T) { runContractReaderBatchGetLatestValuesInterfaceTests(t, tester, mockRun) }) + t.Run("QueryKey", func(t T) { runQueryKeyInterfaceTests(t, tester) }) + t.Run("QueryKeys", func(t T) { runQueryKeysInterfaceTests(t, tester) }) + }) } -func runContractReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], mockRun bool) { +type SomeDynamicTopicEvent struct { + Field string +} + +type sequenceWithKey struct { + types.Sequence + Key string +} + +func runQueryKeysInterfaceTests[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T]) { + tests := []Testcase[T]{ + { + Name: ContractReaderQueryKeysReturnsDataTwoEventTypes, + Test: func(t T) { + ctx := tests.Context(t) + cr := tester.GetContractReader(t) + bindings := tester.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + boundContract := BindingsByName(bindings, AnyContractName)[0] + + expectedSequenceData := createMixedEventTypeSequence(t, tester, boundContract) + + ts := &TestStruct{} + require.Eventually(t, func() bool { + contractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: EventName}, + SequenceDataType: ts, + } + + ds := SomeDynamicTopicEvent{} + secondContractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: DynamicTopicEventName}, + SequenceDataType: &ds, + } + + sequencesIter, err := cr.QueryKeys(ctx, []types.ContractKeyFilter{secondContractFilter, contractFilter}, query.LimitAndSort{}) + if err != nil { + return false + } + + sequences := make([]sequenceWithKey, 0) + for k, s := range sequencesIter { + sequences = append(sequences, sequenceWithKey{Sequence: s, Key: k}) + } + + return sequenceDataEqual(expectedSequenceData, sequences) + }, tester.MaxWaitTimeForEvents(), time.Millisecond*10) + }, + }, + + { + Name: ContractReaderQueryKeysNotFound, + Test: func(t T) { + ctx := tests.Context(t) + cr := tester.GetContractReader(t) + bindings := tester.GetBindings(t) + bound := BindingsByName(bindings, AnyContractName)[0] + + require.NoError(t, cr.Bind(ctx, tester.GetBindings(t))) + + contractFilter := types.ContractKeyFilter{ + Contract: bound, + KeyFilter: query.KeyFilter{Key: EventName}, + SequenceDataType: &TestStruct{}, + } + + logsIter, err := cr.QueryKeys(ctx, []types.ContractKeyFilter{contractFilter}, query.LimitAndSort{}) + require.NoError(t, err) + var logs []types.Sequence + for _, log := range logsIter { + logs = append(logs, log) + } + assert.Len(t, logs, 0) + }, + }, + + { + Name: ContractReaderQueryKeysReturnsDataAsValuesDotValue, + Test: func(t T) { + ctx := tests.Context(t) + cr := tester.GetContractReader(t) + bindings := tester.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + bound := BindingsByName(bindings, AnyContractName)[0] + + expectedSequenceData := createMixedEventTypeSequence(t, tester, bound) + + var value values.Value + require.Eventually(t, func() bool { + contractFilter := types.ContractKeyFilter{ + Contract: bound, + KeyFilter: query.KeyFilter{Key: EventName}, + SequenceDataType: &value, + } + + secondContractFilter := types.ContractKeyFilter{ + Contract: bound, + KeyFilter: query.KeyFilter{Key: DynamicTopicEventName}, + SequenceDataType: &value, + } + + sequencesIter, err := cr.QueryKeys(ctx, []types.ContractKeyFilter{contractFilter, secondContractFilter}, query.LimitAndSort{}) + if err != nil { + return false + } + + sequences := make([]sequenceWithKey, 0) + for k, s := range sequencesIter { + sequences = append(sequences, sequenceWithKey{Sequence: s, Key: k}) + } + + if len(expectedSequenceData) != len(sequences) { + return false + } + + for i, sequence := range sequences { + switch sequence.Key { + case EventName: + val := *sequences[i].Data.(*values.Value) + ts := TestStruct{} + err = val.UnwrapTo(&ts) + require.NoError(t, err) + assert.Equal(t, expectedSequenceData[i], &ts) + case DynamicTopicEventName: + val := *sequences[i].Data.(*values.Value) + ds := SomeDynamicTopicEvent{} + err = val.UnwrapTo(&ds) + require.NoError(t, err) + assert.Equal(t, expectedSequenceData[i], &ds) + default: + return false + } + } + + return true + }, tester.MaxWaitTimeForEvents(), time.Millisecond*10) + }, + }, + + { + Name: ContractReaderQueryKeysCanFilterWithValueComparator, + Test: func(t T) { + ctx := tests.Context(t) + cr := tester.GetContractReader(t) + bindings := tester.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + boundContract := BindingsByName(bindings, AnyContractName)[0] + + expectedSequenceData := createMixedEventTypeSequence(t, tester, boundContract) + + ts := &TestStruct{} + require.Eventually(t, func() bool { + contractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: EventName, + Expressions: []query.Expression{ + query.Comparator("Field", + primitives.ValueComparator{ + Value: 2, + Operator: primitives.Gte, + }, + primitives.ValueComparator{ + Value: 3, + Operator: primitives.Lte, + }), + }}, + SequenceDataType: ts, + } + + ds := SomeDynamicTopicEvent{} + secondContractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: DynamicTopicEventName}, + SequenceDataType: &ds, + } + + sequencesIter, err := cr.QueryKeys(ctx, []types.ContractKeyFilter{contractFilter, secondContractFilter}, query.LimitAndSort{}) + if err != nil { + return false + } + + sequences := make([]sequenceWithKey, 0) + for k, s := range sequencesIter { + sequences = append(sequences, sequenceWithKey{Sequence: s, Key: k}) + } + + expectedSequenceData = expectedSequenceData[2:] + return sequenceDataEqual(expectedSequenceData, sequences) + }, tester.MaxWaitTimeForEvents(), time.Millisecond*500) + }, + }, + { + Name: ContractReaderQueryKeysCanLimitResultsWithCursor, + Test: func(t T) { + ctx := tests.Context(t) + cr := tester.GetContractReader(t) + bindings := tester.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + boundContract := BindingsByName(bindings, AnyContractName)[0] + + var expectedSequenceData []any + + ts1 := CreateTestStruct[T](0, tester) + expectedSequenceData = append(expectedSequenceData, &ts1) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](1, tester) + expectedSequenceData = append(expectedSequenceData, &ts2) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + + ds1 := SomeDynamicTopicEvent{Field: "1"} + expectedSequenceData = append(expectedSequenceData, &ds1) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEventWithDynamicTopic, ds1, boundContract, types.Unconfirmed) + + ts3 := CreateTestStruct[T](2, tester) + expectedSequenceData = append(expectedSequenceData, &ts3) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + + ds2 := SomeDynamicTopicEvent{Field: "2"} + expectedSequenceData = append(expectedSequenceData, &ds2) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEventWithDynamicTopic, ds2, boundContract, types.Unconfirmed) + + ts4 := CreateTestStruct[T](3, tester) + expectedSequenceData = append(expectedSequenceData, &ts4) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts4, boundContract, types.Finalized) + + require.Eventually(t, func() bool { + var allSequences []sequenceWithKey + contractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: EventName, Expressions: []query.Expression{ + query.Confidence(primitives.Finalized), + }}, + SequenceDataType: &TestStruct{}, + } + ds := SomeDynamicTopicEvent{} + secondContractFilter := types.ContractKeyFilter{ + Contract: boundContract, + KeyFilter: query.KeyFilter{Key: DynamicTopicEventName, Expressions: []query.Expression{ + query.Confidence(primitives.Finalized), + }}, + SequenceDataType: &ds, + } + + limit := query.LimitAndSort{ + SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)}, + Limit: query.CountLimit(3), + } + + for idx := 0; idx < len(expectedSequenceData)/2; idx++ { + // sequences from queryKey without limit and sort should be in descending order + sequencesIter, err := cr.QueryKeys(ctx, []types.ContractKeyFilter{secondContractFilter, contractFilter}, limit) + require.NoError(t, err) + + sequences := make([]sequenceWithKey, 0) + for k, s := range sequencesIter { + sequences = append(sequences, sequenceWithKey{Sequence: s, Key: k}) + } + + if len(sequences) == 0 { + continue + } + + limit.Limit = query.CursorLimit(sequences[len(sequences)-1].Cursor, query.CursorFollowing, 3) + allSequences = append(allSequences, sequences...) + } + + return sequenceDataEqual(expectedSequenceData, allSequences) + }, tester.MaxWaitTimeForEvents(), 500*time.Millisecond) + }, + }, + } + + RunTests(t, tester, tests) +} + +func createMixedEventTypeSequence[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], boundContract types.BoundContract) []any { + var expectedSequenceData []any + + ts1 := CreateTestStruct[T](0, tester) + expectedSequenceData = append(expectedSequenceData, &ts1) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](1, tester) + expectedSequenceData = append(expectedSequenceData, &ts2) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + + ds1 := SomeDynamicTopicEvent{Field: "1"} + expectedSequenceData = append(expectedSequenceData, &ds1) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEventWithDynamicTopic, ds1, boundContract, types.Unconfirmed) + + ts3 := CreateTestStruct[T](2, tester) + expectedSequenceData = append(expectedSequenceData, &ts3) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + + ds2 := SomeDynamicTopicEvent{Field: "2"} + expectedSequenceData = append(expectedSequenceData, &ds2) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEventWithDynamicTopic, ds2, boundContract, types.Unconfirmed) + + ts4 := CreateTestStruct[T](3, tester) + expectedSequenceData = append(expectedSequenceData, &ts4) + _ = SubmitTransactionToCW(t, tester, MethodTriggeringEvent, ts4, boundContract, types.Unconfirmed) + + return expectedSequenceData +} + +func sequenceDataEqual(expectedSequenceData []any, sequences []sequenceWithKey) bool { + if len(expectedSequenceData) != len(sequences) { + return false + } + + for i, sequence := range sequences { + if !reflect.DeepEqual(sequence.Data, expectedSequenceData[i]) { + return false + } + } + + return true +} + +func runContractReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], mockRun bool) { tests := []Testcase[T]{ { Name: ContractReaderGetLatestValueAsValuesDotValue, @@ -444,7 +783,6 @@ func runContractReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Ch } func runContractReaderBatchGetLatestValuesInterfaceTests[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], mockRun bool) { - testCases := []Testcase[T]{ { Name: ContractReaderBatchGetLatestValue, @@ -456,7 +794,7 @@ func runContractReaderBatchGetLatestValuesInterfaceTests[T TestingT[T]](t T, tes batchCallEntry := make(BatchCallEntry) batchCallEntry[bound] = ContractBatchEntry{{Name: MethodTakingLatestParamsReturningTestStruct, ReturnValue: &firstItem}} - batchChainWrite(t, tester, batchCallEntry, mockRun) + batchContractWrite(t, tester, batchCallEntry, mockRun) // setup call data params, actual := &LatestParams{I: 1}, &TestStruct{} @@ -618,7 +956,7 @@ func runContractReaderBatchGetLatestValuesInterfaceTests[T TestingT[T]](t T, tes types.BatchRead{ReadName: MethodTakingLatestParamsReturningTestStruct, Params: &LatestParams{I: 1 + i}, ReturnVal: &TestStruct{}}, ) } - batchChainWrite(t, tester, batchCallEntry, mockRun) + batchContractWrite(t, tester, batchCallEntry, mockRun) ctx := tests.Context(t) cr := tester.GetContractReader(t) @@ -654,7 +992,7 @@ func runContractReaderBatchGetLatestValuesInterfaceTests[T TestingT[T]](t T, tes batchGetLatestValueRequest[bound1] = append(batchGetLatestValueRequest[bound1], types.BatchRead{ReadName: MethodTakingLatestParamsReturningTestStruct, Params: &LatestParams{I: 1 + i}, ReturnVal: &TestStruct{}}) batchGetLatestValueRequest[bound2] = append(batchGetLatestValueRequest[bound2], types.BatchRead{ReadName: MethodTakingLatestParamsReturningTestStruct, Params: &LatestParams{I: 1 + i}, ReturnVal: &TestStruct{}}) } - batchChainWrite(t, tester, batchCallEntry, mockRun) + batchContractWrite(t, tester, batchCallEntry, mockRun) ctx := tests.Context(t) cr := tester.GetContractReader(t) diff --git a/pkg/types/interfacetests/utils.go b/pkg/types/interfacetests/utils.go index 41c2eb242..5f81cd206 100644 --- a/pkg/types/interfacetests/utils.go +++ b/pkg/types/interfacetests/utils.go @@ -8,9 +8,10 @@ import ( "time" "github.com/google/uuid" - "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" @@ -56,22 +57,24 @@ type TestingT[T any] interface { // Tests execution utility function that will consider enabled / disabled test cases according to // Basic Tester configuration. func RunTests[T TestingT[T]](t T, tester BasicTester[T], tests []Testcase[T]) { - for _, test := range tests { - if !tester.IsDisabled(test.Name) { - t.Run(test.Name+" for "+tester.Name(), func(t T) { - tester.Setup(t) - test.Test(t) - }) + t.Run(tester.Name(), func(t T) { + for _, test := range tests { + if !tester.IsDisabled(test.Name) { + t.Run(test.Name, func(t T) { + tester.Setup(t) + test.Test(t) + }) + } } - } + }) } -// Batch chain write takes a batch call entry and writes it to the chain using the ChainWriter. -func batchChainWrite[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], batchCallEntry BatchCallEntry, mockRun bool) { +// Batch contract write takes a batch call entry and writes it to the chain using the ContractWriter. +func batchContractWrite[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], batchCallEntry BatchCallEntry, mockRun bool) { // This is necessary because the mock helper function requires the entire batchCallEntry rather than an individual testStruct if mockRun { - cw := tester.GetChainWriter(t) - err := cw.SubmitTransaction(tests.Context(t), AnyContractName, "batchChainWrite", batchCallEntry, "", "", nil, big.NewInt(0)) + cw := tester.GetContractWriter(t) + err := cw.SubmitTransaction(tests.Context(t), AnyContractName, "batchContractWrite", batchCallEntry, "", "", nil, big.NewInt(0)) require.NoError(t, err) return } @@ -94,11 +97,11 @@ func batchChainWrite[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T } } -// SubmitTransactionToCW submits a transaction to the ChainWriter and waits for it to reach the given status. +// SubmitTransactionToCW submits a transaction to the ContractWriter and waits for it to reach the given status. func SubmitTransactionToCW[T TestingT[T]](t T, tester ChainComponentsInterfaceTester[T], method string, args any, contract types.BoundContract, status types.TransactionStatus) string { tester.DirtyContracts() txID := uuid.New().String() - cw := tester.GetChainWriter(t) + cw := tester.GetContractWriter(t) err := cw.SubmitTransaction(tests.Context(t), contract.Name, method, args, txID, contract.Address, nil, big.NewInt(0)) require.NoError(t, err) @@ -125,7 +128,7 @@ func WaitForTransactionStatus[T TestingT[T]](t T, tester ChainComponentsInterfac tester.GenerateBlocksTillConfidenceLevel(t, "", "", primitives.Finalized) return nil } - current, err := tester.GetChainWriter(t).GetTransactionStatus(ctx, txID) + current, err := tester.GetContractWriter(t).GetTransactionStatus(ctx, txID) if err != nil { return fmt.Errorf("failed to get transaction status: %w", err) } diff --git a/pkg/types/query/key_filter.go b/pkg/types/query/key_filter.go new file mode 100644 index 000000000..d5b5b78c3 --- /dev/null +++ b/pkg/types/query/key_filter.go @@ -0,0 +1,164 @@ +package query + +import ( + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" +) + +// IndexedSequencesKeyFilter creates a KeyFilter that filters logs for the provided sequence property values at the +// specified property name. Sequence value filters are 'OR'ed together. A sequence read name is the value that +// identifies the sequence type. The signature value name is the sequence property to apply the filter to and the +// sequence values are the individual values to search for in the provided property. +func IndexedSequencesKeyFilter( + readName string, + comparatorName string, + values []string, + confidence primitives.ConfidenceLevel, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + filtersForValues(comparatorName, values), + Confidence(confidence), + }, + } +} + +// IndexedSequencesByBlockRangeKeyFilter creates a KeyFilter that filters sequences for the provided property values at +// the specified property name. Value filters are 'OR'ed together and results are limited by provided cursor range. A +// read name is the value that identifies the sequence type. The signature property name is the sequence property to +// apply the filter to and the sequence values are the individual values to search for in the provided property. +func IndexedSequencesByBlockRangeKeyFilter( + readName string, + start, end string, + comparatorName string, + values []string, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + filtersForValues(comparatorName, values), + Block(start, primitives.Gte), + Block(end, primitives.Lte), + }, + } +} + +// IndexedSequencesValueGreaterThanKeyFilter creates a KeyFilter that filters sequences for the provided property value +// and name at or above the specified confidence level. A sequence read name is the value that identifies the sequence +// type. The property name is the sequence property to apply the filter to and the value is the individual value to +// search for in the provided property. +func IndexedSequencesValueGreaterThanKeyFilter( + readName string, + comparatorName, value string, + confidence primitives.ConfidenceLevel, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + valueComparator(comparatorName, value, primitives.Gte), + Confidence(confidence), + }, + } +} + +// IndexedSequencesValueRangeKeyFilter creates a KeyFilter that filters logs on the provided sequence property between +// the provided min and max, endpoints inclusive. A sequence read name is the value that identifies the sequence type. +func IndexedSequencesValueRangeKeyFilter( + readName string, + comparatorName string, + min, max string, + confidence primitives.ConfidenceLevel, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + valueComparator(comparatorName, min, primitives.Gte), + valueComparator(comparatorName, max, primitives.Lte), + Confidence(confidence), + }, + } +} + +// IndexedSequencesByTxHashKeyFilter creates a KeyFilter that filters logs for the provided transaction hash. A sequence +// read name is the value that identifies the sequence type. +func IndexedSequencesByTxHashKeyFilter( + readName, txHash string, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + TxHash(txHash), + }, + } +} + +// SequencesByBlockRangeKeyFilter creates a KeyFilter that filters sequences for the provided block range, endpoints inclusive. +func SequencesByBlockRangeKeyFilter( + readName string, + start, end string, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + Block(start, primitives.Gte), + Block(end, primitives.Lte), + }, + } +} + +// SequencesCreatedAfterKeyFilter creates a KeyFilter that filters sequences for after but not equal to the provided time value. +func SequencesCreatedAfterKeyFilter( + readName string, + timestamp time.Time, + confidence primitives.ConfidenceLevel, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + Timestamp(uint64(timestamp.Unix()), primitives.Gt), + Confidence(confidence), + }, + } +} + +// IndexedSequencesCreatedAfterKeyFilter creates a KeyFilter that filters sequences for the provided property and values +// created after the provided time value. Sequence property values filters are 'OR'ed. A sequence read name is the value +// that identifies the sequence type. +func IndexedSequencesCreatedAfterKeyFilter( + readName string, + comparatorName string, + values []string, + timestamp time.Time, + confidence primitives.ConfidenceLevel, +) KeyFilter { + return KeyFilter{ + Key: readName, + Expressions: []Expression{ + filtersForValues(comparatorName, values), + Timestamp(uint64(timestamp.Unix()), primitives.Gt), + Confidence(confidence), + }, + } +} + +func valueComparator(comparatorName, value string, op primitives.ComparisonOperator) Expression { + return Comparator(comparatorName, primitives.ValueComparator{ + Value: value, + Operator: op, + }) +} + +func filtersForValues(comparatorName string, values []string) Expression { + valueFilters := BoolExpression{ + Expressions: make([]Expression, len(values)), + BoolOperator: OR, + } + + for idx, value := range values { + valueFilters.Expressions[idx] = valueComparator(comparatorName, value, primitives.Eq) + } + + return Expression{BoolExpression: valueFilters} +} diff --git a/pkg/types/query/key_filter_test.go b/pkg/types/query/key_filter_test.go new file mode 100644 index 000000000..5f7cf0d9a --- /dev/null +++ b/pkg/types/query/key_filter_test.go @@ -0,0 +1,200 @@ +package query_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/types/query" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" +) + +func TestIndexedSequencesKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.IndexedSequencesKeyFilter("readName", "property", []string{"value1", "value2"}, primitives.Finalized) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value1", Operator: primitives.Eq}}, + }, + }, + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value2", Operator: primitives.Eq}}, + }, + }, + }, + BoolOperator: query.OR, + }}, + {Primitive: &primitives.Confidence{ConfidenceLevel: primitives.Finalized}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestIndexedSequencesByBlockRangeKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.IndexedSequencesByBlockRangeKeyFilter("readName", "start", "end", "property", []string{"value1", "value2"}) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value1", Operator: primitives.Eq}}, + }, + }, + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value2", Operator: primitives.Eq}}, + }, + }, + }, + BoolOperator: query.OR, + }}, + {Primitive: &primitives.Block{Block: "start", Operator: primitives.Gte}}, + {Primitive: &primitives.Block{Block: "end", Operator: primitives.Lte}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestIndexedSequencesValueGreaterThanKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.IndexedSequencesValueGreaterThanKeyFilter("readName", "property", "value1", primitives.Finalized) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value1", Operator: primitives.Gte}}, + }, + }, + {Primitive: &primitives.Confidence{ConfidenceLevel: primitives.Finalized}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestIndexedSequencesValueRangeKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.IndexedSequencesValueRangeKeyFilter("readName", "property", "min", "max", primitives.Finalized) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "min", Operator: primitives.Gte}}, + }, + }, + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "max", Operator: primitives.Lte}}, + }, + }, + {Primitive: &primitives.Confidence{ConfidenceLevel: primitives.Finalized}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestIndexedSequencesByTxHashKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.IndexedSequencesByTxHashKeyFilter("readName", "hash") + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {Primitive: &primitives.TxHash{TxHash: "hash"}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestSequencesByBlockRangeKeyFilter(t *testing.T) { + t.Parallel() + + filter := query.SequencesByBlockRangeKeyFilter("readName", "start", "end") + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {Primitive: &primitives.Block{Block: "start", Operator: primitives.Gte}}, + {Primitive: &primitives.Block{Block: "end", Operator: primitives.Lte}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestSequencesCreatedAfterKeyFilter(t *testing.T) { + t.Parallel() + + now := time.Now() + + filter := query.SequencesCreatedAfterKeyFilter("readName", now, primitives.Finalized) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {Primitive: &primitives.Timestamp{Timestamp: uint64(now.Unix()), Operator: primitives.Gt}}, + {Primitive: &primitives.Confidence{ConfidenceLevel: primitives.Finalized}}, + }, + } + + require.Equal(t, expected, filter) +} + +func TestIndexedSequencesCreatedAfterKeyFilter(t *testing.T) { + t.Parallel() + + now := time.Now() + + filter := query.IndexedSequencesCreatedAfterKeyFilter("readName", "property", []string{"value1", "value2"}, now, primitives.Finalized) + expected := query.KeyFilter{ + Key: "readName", + Expressions: []query.Expression{ + {BoolExpression: query.BoolExpression{ + Expressions: []query.Expression{ + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value1", Operator: primitives.Eq}}, + }, + }, + { + Primitive: &primitives.Comparator{ + Name: "property", + ValueComparators: []primitives.ValueComparator{{Value: "value2", Operator: primitives.Eq}}, + }, + }, + }, + BoolOperator: query.OR, + }}, + {Primitive: &primitives.Timestamp{Timestamp: uint64(now.Unix()), Operator: primitives.Gt}}, + {Primitive: &primitives.Confidence{ConfidenceLevel: primitives.Finalized}}, + }, + } + + require.Equal(t, expected, filter) +} diff --git a/pkg/types/relayer.go b/pkg/types/relayer.go index ea87f1d17..d482e75e8 100644 --- a/pkg/types/relayer.go +++ b/pkg/types/relayer.go @@ -97,9 +97,9 @@ type ChainService interface { type Relayer interface { ChainService - // NewChainWriter returns a new ChainWriter. + // NewContractWriter returns a new ContractWriter. // The format of config depends on the implementation. - NewChainWriter(ctx context.Context, config []byte) (ChainWriter, error) + NewContractWriter(ctx context.Context, config []byte) (ContractWriter, error) // NewContractReader returns a new ContractReader. // The format of contractReaderConfig depends on the implementation. diff --git a/pkg/values/value.go b/pkg/values/value.go index 09f952c17..ac109fd9c 100644 --- a/pkg/values/value.go +++ b/pkg/values/value.go @@ -8,7 +8,6 @@ import ( "reflect" "time" - "github.com/go-viper/mapstructure/v2" "github.com/shopspring/decimal" "github.com/smartcontractkit/chainlink-common/pkg/values/pb" @@ -303,12 +302,32 @@ func fromBigIntValueProto(biv *pb.BigInt) *BigInt { } func CreateMapFromStruct(v any) (*Map, error) { - var resultMap map[string]interface{} + resultMap := map[string]any{} - err := mapstructure.Decode(v, &resultMap) - if err != nil { - return nil, err + // use reflect to handle nested types as an interface + rv := reflect.ValueOf(v) + rt := reflect.TypeOf(v) + + if rv.Kind() != reflect.Struct { + return nil, errors.New("input must be of struct type") } + + for i := 0; i < rv.NumField(); i++ { + field := rt.Field(i) + // ignore private fields + if !field.IsExported() { + continue + } + // for backwards compatibility, use tagged mapstructure tag as key if provided + msTag := field.Tag.Get("mapstructure") + key := msTag + if key == "" { + key = field.Name + } + + resultMap[key] = rv.Field(i).Interface() + } + return NewMap(resultMap) } diff --git a/pkg/workflows/sdk/builder.go b/pkg/workflows/sdk/builder.go index 63bff5dce..138e55cf3 100644 --- a/pkg/workflows/sdk/builder.go +++ b/pkg/workflows/sdk/builder.go @@ -125,18 +125,9 @@ func (c *capDefinitionImpl[O]) self() CapDefinition[O] { func (c *capDefinitionImpl[O]) private() {} -type NewWorkflowParams struct { - Owner string - Name string -} - -func NewWorkflowSpecFactory( - params NewWorkflowParams, -) *WorkflowSpecFactory { +func NewWorkflowSpecFactory() *WorkflowSpecFactory { return &WorkflowSpecFactory{ spec: &WorkflowSpec{ - Owner: params.Owner, - Name: params.Name, Triggers: make([]StepDefinition, 0), Actions: make([]StepDefinition, 0), Consensus: make([]StepDefinition, 0), diff --git a/pkg/workflows/sdk/builder_test.go b/pkg/workflows/sdk/builder_test.go index d3901843a..ba3976661 100644 --- a/pkg/workflows/sdk/builder_test.go +++ b/pkg/workflows/sdk/builder_test.go @@ -28,7 +28,6 @@ import ( // This implicitly tests the code generators functionally, as the generated code is used in the tests. type Config struct { - Workflow sdk.NewWorkflowParams Streams *streams.TriggerConfig Ocr *ocr3.DataFeedsConsensusConfig ChainWriter *chainwriter.TargetConfig @@ -41,7 +40,7 @@ func NewWorkflowSpec(rawConfig []byte) (*sdk.WorkflowSpecFactory, error) { return nil, err } - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() streamsTrigger := conf.Streams.New(workflow) consensus := conf.Ocr.New(workflow, "ccip_feeds", ocr3.DataFeedsConsensusInput{ Observations: sdk.ListOf[streams.Feed](streamsTrigger)}, @@ -55,7 +54,6 @@ func NewWorkflowSpec(rawConfig []byte) (*sdk.WorkflowSpecFactory, error) { // ModifiedConfig, and the test it's used in, show how you can structure config to remove copy/paste issues when data // needs to be repeated in multiple capability configurations. type ModifiedConfig struct { - Workflow sdk.NewWorkflowParams AllowedPartialStaleness string MaxFrequencyMs uint64 DefaultHeartbeat uint64 `yaml:"default_heartbeat" json:"default_heartbeat"` @@ -114,7 +112,7 @@ func NewWorkflowRemapped(rawConfig []byte) (*sdk.WorkflowSpecFactory, error) { } ocr3Config.AggregationConfig.Feeds = feeds - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() streamsTrigger := streamsConfig.New(workflow) consensus := ocr3Config.New(workflow, "ccip_feeds", ocr3.DataFeedsConsensusInput{ @@ -134,7 +132,7 @@ func NewWorkflowSpecFromPrimitives(rawConfig []byte) (*sdk.WorkflowSpecFactory, return nil, err } - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() notStreamsTrigger := conf.NotStream.New(workflow) md := streams.NewSignersMetadataFromFields( @@ -213,8 +211,6 @@ func TestBuilder_ValidSpec(t *testing.T) { require.NoError(t, err) expected := sdk.WorkflowSpec{ - Name: "notccipethsep", - Owner: "0x00000000000000000000000000000000000000aa", Triggers: []sdk.StepDefinition{ { ID: "notstreams@1.0.0", @@ -291,14 +287,12 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("maps work correctly", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1", Number: 1}.New(workflow) mapaction.ActionConfig{}.New(workflow, "ref", mapaction.ActionInput{Payload: sdk.Map[string, mapaction.ActionInputsPayload](map[string]sdk.CapDefinition[string]{"Foo": trigger.CoolOutput()})}) spec, err := workflow.Spec() require.NoError(t, err) testutils.AssertWorkflowSpec(t, sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", @@ -328,14 +322,12 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("any maps work correctly", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1", Number: 1}.New(workflow) anymapaction.MapActionConfig{}.New(workflow, "ref", anymapaction.MapActionInput{Payload: sdk.AnyMap[anymapaction.MapActionInputsPayload](sdk.CapMap{"Foo": trigger.CoolOutput()})}) spec, err := workflow.Spec() require.NoError(t, err) testutils.AssertWorkflowSpec(t, sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", @@ -365,7 +357,7 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("ToListDefinition works correctly for list elements", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := listtrigger.TriggerConfig{Name: "1"}.New(workflow) asList := sdk.ToListDefinition[string](trigger.CoolOutput()) sdk.Compute1(workflow, "compute", sdk.Compute1Inputs[[]string]{Arg0: asList}, func(_ sdk.Runtime, inputs []string) (string, error) { @@ -379,8 +371,6 @@ func TestBuilder_ValidSpec(t *testing.T) { require.NoError(t, err) testutils.AssertWorkflowSpec(t, sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "list@1.0.0", @@ -422,7 +412,7 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("ToListDefinition works correctly for built up lists", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1"}.New(workflow) asList := sdk.ToListDefinition(sdk.ListOf(trigger.CoolOutput())) sdk.Compute1(workflow, "compute", sdk.Compute1Inputs[[]string]{Arg0: asList}, func(_ sdk.Runtime, inputs []string) (string, error) { @@ -436,8 +426,6 @@ func TestBuilder_ValidSpec(t *testing.T) { require.NoError(t, err) testutils.AssertWorkflowSpec(t, sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", @@ -479,7 +467,7 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("ToListDefinition works correctly for hard-coded lists", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "1"}.New(workflow) list := sdk.ToListDefinition(sdk.ConstantDefinition([]string{"1", "2"})) sdk.Compute2(workflow, "compute", sdk.Compute2Inputs[string, []string]{Arg0: trigger.CoolOutput(), Arg1: list}, func(_ sdk.Runtime, t string, l []string) (string, error) { @@ -493,8 +481,6 @@ func TestBuilder_ValidSpec(t *testing.T) { require.NoError(t, err) testutils.AssertWorkflowSpec(t, sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "basic-test-trigger@1.0.0", @@ -542,14 +528,14 @@ func TestBuilder_ValidSpec(t *testing.T) { }) t.Run("AnyListOf works like list of but returns a type any", func(t *testing.T) { - workflow1 := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow1 := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "foo", Number: 0} list := sdk.ListOf(trigger.New(workflow1).CoolOutput()) sdk.Compute1(workflow1, "compute", sdk.Compute1Inputs[[]string]{Arg0: list}, func(_ sdk.Runtime, inputs []string) (string, error) { return inputs[0], nil }) - workflow2 := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow2 := sdk.NewWorkflowSpecFactory() anyList := sdk.AnyListOf(trigger.New(workflow2).CoolOutput()) sdk.Compute1(workflow2, "compute", sdk.Compute1Inputs[[]any]{Arg0: anyList}, func(_ sdk.Runtime, inputs []any) (any, error) { return inputs[0], nil @@ -567,7 +553,7 @@ func TestBuilder_ValidSpec(t *testing.T) { conf, err := UnmarshalYaml[Config](sepoliaConfig) require.NoError(t, err) - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() streamsTrigger := conf.Streams.New(workflow) consensus := conf.Ocr.New(workflow, "ccip_feeds", ocr3.DataFeedsConsensusInput{ Observations: sdk.ListOf[streams.Feed](streamsTrigger)}, @@ -589,7 +575,7 @@ func TestBuilder_ValidSpec(t *testing.T) { conf, err := UnmarshalYaml[Config](sepoliaConfig) require.NoError(t, err) - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() streamsTrigger := conf.Streams.New(workflow) consensus := conf.Ocr.New(workflow, "", ocr3.DataFeedsConsensusInput{ Observations: sdk.ListOf[streams.Feed](streamsTrigger)}, @@ -605,7 +591,7 @@ func TestBuilder_ValidSpec(t *testing.T) { conf, err := UnmarshalYaml[Config](sepoliaConfig) require.NoError(t, err) - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() badStep := sdk.Step[streams.Feed]{ Definition: sdk.StepDefinition{ ID: "streams-trigger@1.0.0", @@ -632,7 +618,7 @@ func TestBuilder_ValidSpec(t *testing.T) { conf, err := UnmarshalYaml[Config](sepoliaConfig) require.NoError(t, err) - workflow := sdk.NewWorkflowSpecFactory(conf.Workflow) + workflow := sdk.NewWorkflowSpecFactory() streamsTrigger := conf.Streams.New(workflow) consensus := conf.Ocr.New(workflow, "ccip_feeds", ocr3.DataFeedsConsensusInput{ Observations: sdk.ListOf[streams.Feed](streamsTrigger)}, @@ -665,7 +651,6 @@ func runSepoliaStagingTest(t *testing.T, config []byte, gen func([]byte) (*sdk.W } type NotStreamsConfig struct { - Workflow sdk.NewWorkflowParams NotStream *notstreams.TriggerConfig `yaml:"not_stream" json:"not_stream"` Ocr *ModifiedConsensusConfig ChainWriter *chainwriter.TargetConfig diff --git a/pkg/workflows/sdk/compute_test.go b/pkg/workflows/sdk/compute_test.go index 08c0c8344..5f024a81e 100644 --- a/pkg/workflows/sdk/compute_test.go +++ b/pkg/workflows/sdk/compute_test.go @@ -33,7 +33,10 @@ func TestCompute(t *testing.T) { }, Timestamp: 1690838088, } - nsf, err := values.CreateMapFromStruct(map[string]any{"Arg0": anyNotStreamsInput}) + structToMap, err := values.CreateMapFromStruct(anyNotStreamsInput) + require.NoError(t, err) + + nsf, err := values.NewMap(map[string]any{"Arg0": structToMap}) require.NoError(t, err) t.Run("creates correct workflow spec", func(t *testing.T) { @@ -42,8 +45,6 @@ func TestCompute(t *testing.T) { spec, err2 := workflow.Spec() require.NoError(t, err2) expectedSpec := sdk.WorkflowSpec{ - Name: "name", - Owner: "owner", Triggers: []sdk.StepDefinition{ { ID: "notstreams@1.0.0", @@ -179,10 +180,7 @@ type ComputeOutput struct { } func createComputeWithConfigWorkflow(config ComputeConfig, fn func(_ sdk.Runtime, config ComputeConfig, input basictrigger.TriggerOutputs) (ComputeOutput, error)) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{ - Owner: "owner", - Name: "name", - }) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) @@ -202,10 +200,7 @@ func createComputeWithConfigWorkflow(config ComputeConfig, fn func(_ sdk.Runtime } func createWorkflow(fn func(_ sdk.Runtime, inputFeed notstreams.Feed) ([]streams.Feed, error)) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{ - Owner: "owner", - Name: "name", - }) + workflow := sdk.NewWorkflowSpecFactory() trigger := notstreams.TriggerConfig{MaxFrequencyMs: 5000}.New(workflow) computed := sdk.Compute1(workflow, "Compute", sdk.Compute1Inputs[notstreams.Feed]{Arg0: trigger}, fn) diff --git a/pkg/workflows/sdk/testdata/fixtures/workflows/expected_sepolia.yaml b/pkg/workflows/sdk/testdata/fixtures/workflows/expected_sepolia.yaml index aeebc544d..b549145c0 100644 --- a/pkg/workflows/sdk/testdata/fixtures/workflows/expected_sepolia.yaml +++ b/pkg/workflows/sdk/testdata/fixtures/workflows/expected_sepolia.yaml @@ -1,8 +1,6 @@ # At the time of writing, this was taken form the staging deployment # trigger ref was added so it can match the way it's done by the builder. It's implied as trigger today, and not harmful to add. # One of the heartbeat and deviation values were modified so that the defaults example can be shown to work. -name: "ccipethsep" -owner: "0x00000000000000000000000000000000000000aa" triggers: - id: "streams-trigger@1.0.0" ref: "trigger" @@ -76,4 +74,4 @@ targets: config: address: "0xE0082363396985ae2FdcC3a9F816A586Eed88416" deltaStage: "45s" - schedule: "oneAtATime" \ No newline at end of file + schedule: "oneAtATime" diff --git a/pkg/workflows/sdk/testdata/fixtures/workflows/notstreamssepolia.yaml b/pkg/workflows/sdk/testdata/fixtures/workflows/notstreamssepolia.yaml index 6c0f11acf..2c0cf3556 100644 --- a/pkg/workflows/sdk/testdata/fixtures/workflows/notstreamssepolia.yaml +++ b/pkg/workflows/sdk/testdata/fixtures/workflows/notstreamssepolia.yaml @@ -1,6 +1,3 @@ -workflow: - name: notccipethsep - owner: '0x00000000000000000000000000000000000000aa' not_stream: maxFrequencyMs: 5000 ocr: diff --git a/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia.yaml b/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia.yaml index e332df444..720c08845 100644 --- a/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia.yaml +++ b/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia.yaml @@ -1,6 +1,3 @@ -workflow: - name: ccipethsep - owner: '0x00000000000000000000000000000000000000aa' streams: feedIds: - '0x0003fbba4fce42f65d6032b18aee53efdf526cc734ad296cb57565979d883bdd' diff --git a/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia_defaults.yaml b/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia_defaults.yaml index 76b5f27c2..84019bdc8 100644 --- a/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia_defaults.yaml +++ b/pkg/workflows/sdk/testdata/fixtures/workflows/sepolia_defaults.yaml @@ -1,6 +1,3 @@ -workflow: - name: ccipethsep - owner: '0x00000000000000000000000000000000000000aa' maxFrequencyMs: 5000 default_heartbeat: 3600 default_deviation: '0.05' @@ -29,4 +26,4 @@ chainWriter: deltaStage: 45s schedule: oneAtATime targetChain: 'write_ethereum-testnet-sepolia@1.0.0' -allowedPartialStaleness: '0.5' \ No newline at end of file +allowedPartialStaleness: '0.5' diff --git a/pkg/workflows/sdk/testutils/runner_test.go b/pkg/workflows/sdk/testutils/runner_test.go index 7c5bf9955..b9ec9c2c0 100644 --- a/pkg/workflows/sdk/testutils/runner_test.go +++ b/pkg/workflows/sdk/testutils/runner_test.go @@ -64,7 +64,7 @@ func TestRunner(t *testing.T) { }) t.Run("Run allows hard-coded values", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "tester", Owner: "ryan"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "trigger", Number: 100}.New(workflow) hardCodedInput := basicaction.NewActionOutputsFromFields(sdk.ConstantDefinition("hard-coded")) tTransform := sdk.Compute2[basictrigger.TriggerOutputs, basicaction.ActionOutputs, bool]( @@ -261,7 +261,7 @@ type ComputeConfig struct { func TestCompute(t *testing.T) { t.Run("Inputs don't loose integer types when any is deserialized to", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "foo", Number: 100}.New(workflow) toMap := sdk.Compute1(workflow, "tomap", sdk.Compute1Inputs[string]{Arg0: trigger.CoolOutput()}, func(runtime sdk.Runtime, i0 string) (map[string]any, error) { v, err := strconv.Atoi(i0) @@ -292,7 +292,7 @@ func TestCompute(t *testing.T) { }) t.Run("Config interpolates secrets", func(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "name", Owner: "owner"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "foo", Number: 100}.New(workflow) conf := ComputeConfig{ @@ -321,7 +321,7 @@ func TestCompute(t *testing.T) { } func registrationWorkflow() (*sdk.WorkflowSpecFactory, map[string]any, map[string]any) { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "tester", Owner: "ryan"}) + workflow := sdk.NewWorkflowSpecFactory() testTriggerConfig := map[string]any{"something": "from nothing"} trigger := sdk.Step[int]{ Definition: sdk.StepDefinition{ @@ -369,7 +369,7 @@ func setupAllRunnerMocks(t *testing.T, runner *testutils.Runner) (*testutils.Tri type actionTransform func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (bool, error) func createBasicTestWorkflow(actionTransform actionTransform) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{Name: "tester", Owner: "ryan"}) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "trigger", Number: 100}.New(workflow) tTransform := sdk.Compute1[basictrigger.TriggerOutputs, bool]( workflow, diff --git a/pkg/workflows/utils.go b/pkg/workflows/utils.go index 561b118df..d7aae90b0 100644 --- a/pkg/workflows/utils.go +++ b/pkg/workflows/utils.go @@ -3,6 +3,7 @@ package workflows import ( "crypto/sha256" "encoding/hex" + "strings" ) func EncodeExecutionID(workflowID, eventID string) (string, error) { @@ -19,3 +20,43 @@ func EncodeExecutionID(workflowID, eventID string) (string, error) { return hex.EncodeToString(s.Sum(nil)), nil } + +func GenerateWorkflowIDFromStrings(owner string, workflow []byte, config []byte, secretsURL string) (string, error) { + ownerWithoutPrefix := owner + if strings.HasPrefix(owner, "0x") { + ownerWithoutPrefix = owner[2:] + } + + ownerb, err := hex.DecodeString(ownerWithoutPrefix) + if err != nil { + return "", err + } + + wid, err := GenerateWorkflowID(ownerb, workflow, config, secretsURL) + if err != nil { + return "", err + } + + return hex.EncodeToString(wid[:]), nil +} + +func GenerateWorkflowID(owner []byte, workflow []byte, config []byte, secretsURL string) ([32]byte, error) { + s := sha256.New() + _, err := s.Write(owner) + if err != nil { + return [32]byte{}, err + } + _, err = s.Write([]byte(workflow)) + if err != nil { + return [32]byte{}, err + } + _, err = s.Write([]byte(config)) + if err != nil { + return [32]byte{}, err + } + _, err = s.Write([]byte(secretsURL)) + if err != nil { + return [32]byte{}, err + } + return [32]byte(s.Sum(nil)), nil +} diff --git a/pkg/workflows/utils_test.go b/pkg/workflows/utils_test.go index e66e7ae33..1fccc6839 100644 --- a/pkg/workflows/utils_test.go +++ b/pkg/workflows/utils_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_EncodeExecutionID(t *testing.T) { @@ -38,3 +39,27 @@ func Test_EncodeExecutionID(t *testing.T) { reversed := hex.EncodeToString(s.Sum(nil)) assert.NotEqual(t, reversed, actual) } + +func Test_GenerateWorkflowIDFromStrings(t *testing.T) { + // With prefix + owner := "0x26729408f179371be6433b9585d8427f121bfe82" + got, err := GenerateWorkflowIDFromStrings(owner, []byte("workflow"), []byte("config"), "http://mysecrets.com") + require.NoError(t, err) + assert.NotNil(t, got) + + // Without prefix + owner = "26729408f179371be6433b9585d8427f121bfe82" + got, err = GenerateWorkflowIDFromStrings(owner, []byte("workflow"), []byte("config"), "http://mysecrets.com") + require.NoError(t, err) + assert.NotNil(t, got) + + // Very short; empty but with a prefix + owner = "0x" + got, err = GenerateWorkflowIDFromStrings(owner, []byte("workflow"), []byte("config"), "http://mysecrets.com") + require.NoError(t, err) + assert.NotNil(t, got) + + owner = "invalid" + _, err = GenerateWorkflowIDFromStrings(owner, []byte("workflow"), []byte("config"), "http://mysecrets.com") + assert.ErrorContains(t, err, "encoding/hex") +} diff --git a/pkg/workflows/wasm/host/test/builderr/cmd/main.go b/pkg/workflows/wasm/host/test/builderr/cmd/main.go new file mode 100644 index 000000000..cc88a8079 --- /dev/null +++ b/pkg/workflows/wasm/host/test/builderr/cmd/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + + "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm" + + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" +) + +func BuildWorkflow(config []byte) (*sdk.WorkflowSpecFactory, error) { + // Do something that errors + return nil, errors.New("oops: I couldn't build this workflow") +} + +func main() { + runner := wasm.NewRunner() + workflow, err := BuildWorkflow(runner.Config()) + if err != nil { + runner.ExitWithError(err) + } + runner.Run(workflow) +} diff --git a/pkg/workflows/wasm/host/test/computepanic/cmd/main.go b/pkg/workflows/wasm/host/test/computepanic/cmd/main.go new file mode 100644 index 000000000..cb1f7a705 --- /dev/null +++ b/pkg/workflows/wasm/host/test/computepanic/cmd/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/cli/cmd/testdata/fixtures/capabilities/basictrigger" + "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" +) + +type foo struct { + thing string +} + +func (f *foo) doAThing() { + _ = f.thing +} + +func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { + workflow := sdk.NewWorkflowSpecFactory() + + triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} + trigger := triggerCfg.New(workflow) + + sdk.Compute1[basictrigger.TriggerOutputs, bool]( + workflow, + "transform", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (bool, error) { + var f *foo + f.doAThing() + return false, nil + }) + + return workflow +} + +func main() { + runner := wasm.NewRunner() + workflow := BuildWorkflow(runner.Config()) + runner.Run(workflow) +} diff --git a/pkg/workflows/wasm/host/test/dirs/cmd/main.go b/pkg/workflows/wasm/host/test/dirs/cmd/main.go index a7500974b..8599985f6 100644 --- a/pkg/workflows/wasm/host/test/dirs/cmd/main.go +++ b/pkg/workflows/wasm/host/test/dirs/cmd/main.go @@ -12,12 +12,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/emit/cmd/main.go b/pkg/workflows/wasm/host/test/emit/cmd/main.go index 712b56e59..0d36ca361 100644 --- a/pkg/workflows/wasm/host/test/emit/cmd/main.go +++ b/pkg/workflows/wasm/host/test/emit/cmd/main.go @@ -10,9 +10,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{}, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/env/cmd/main.go b/pkg/workflows/wasm/host/test/env/cmd/main.go index 9dc7190bb..372078b2f 100644 --- a/pkg/workflows/wasm/host/test/env/cmd/main.go +++ b/pkg/workflows/wasm/host/test/env/cmd/main.go @@ -13,12 +13,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/fetch/cmd/main.go b/pkg/workflows/wasm/host/test/fetch/cmd/main.go index d7a71e0a1..2eb8949c8 100644 --- a/pkg/workflows/wasm/host/test/fetch/cmd/main.go +++ b/pkg/workflows/wasm/host/test/fetch/cmd/main.go @@ -12,12 +12,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/fetchlimit/cmd/main.go b/pkg/workflows/wasm/host/test/fetchlimit/cmd/main.go index 0e7fd2998..1aaa19acd 100644 --- a/pkg/workflows/wasm/host/test/fetchlimit/cmd/main.go +++ b/pkg/workflows/wasm/host/test/fetchlimit/cmd/main.go @@ -12,12 +12,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/files/cmd/main.go b/pkg/workflows/wasm/host/test/files/cmd/main.go index ec5f0ac75..492ac47ce 100644 --- a/pkg/workflows/wasm/host/test/files/cmd/main.go +++ b/pkg/workflows/wasm/host/test/files/cmd/main.go @@ -12,12 +12,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/http/cmd/main.go b/pkg/workflows/wasm/host/test/http/cmd/main.go index 68e43662e..bacf8d8b3 100644 --- a/pkg/workflows/wasm/host/test/http/cmd/main.go +++ b/pkg/workflows/wasm/host/test/http/cmd/main.go @@ -12,12 +12,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/log/cmd/main.go b/pkg/workflows/wasm/host/test/log/cmd/main.go index 4c3c04732..4dfbd79b2 100644 --- a/pkg/workflows/wasm/host/test/log/cmd/main.go +++ b/pkg/workflows/wasm/host/test/log/cmd/main.go @@ -10,12 +10,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/rand/cmd/main.go b/pkg/workflows/wasm/host/test/rand/cmd/main.go index fa908a108..ca56c82fd 100644 --- a/pkg/workflows/wasm/host/test/rand/cmd/main.go +++ b/pkg/workflows/wasm/host/test/rand/cmd/main.go @@ -13,9 +13,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{}, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} trigger := triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/runnerapi/cmd/main.go b/pkg/workflows/wasm/host/test/runnerapi/cmd/main.go index 2f0461bb4..4a2ae6d07 100644 --- a/pkg/workflows/wasm/host/test/runnerapi/cmd/main.go +++ b/pkg/workflows/wasm/host/test/runnerapi/cmd/main.go @@ -8,12 +8,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} _ = triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/test/success/cmd/main.go b/pkg/workflows/wasm/host/test/success/cmd/main.go index 2ee9f7bd4..477ba097c 100644 --- a/pkg/workflows/wasm/host/test/success/cmd/main.go +++ b/pkg/workflows/wasm/host/test/success/cmd/main.go @@ -10,12 +10,7 @@ import ( ) func BuildWorkflow(config []byte) *sdk.WorkflowSpecFactory { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "ryan", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() triggerCfg := basictrigger.TriggerConfig{Name: "trigger", Number: 100} _ = triggerCfg.New(workflow) diff --git a/pkg/workflows/wasm/host/wasm_test.go b/pkg/workflows/wasm/host/wasm_test.go index 720f17c9e..3e5335a9d 100644 --- a/pkg/workflows/wasm/host/wasm_test.go +++ b/pkg/workflows/wasm/host/wasm_test.go @@ -29,32 +29,36 @@ import ( ) const ( - successBinaryLocation = "test/success/cmd/testmodule.wasm" - successBinaryCmd = "test/success/cmd" - failureBinaryLocation = "test/fail/cmd/testmodule.wasm" - failureBinaryCmd = "test/fail/cmd" - oomBinaryLocation = "test/oom/cmd/testmodule.wasm" - oomBinaryCmd = "test/oom/cmd" - sleepBinaryLocation = "test/sleep/cmd/testmodule.wasm" - sleepBinaryCmd = "test/sleep/cmd" - filesBinaryLocation = "test/files/cmd/testmodule.wasm" - filesBinaryCmd = "test/files/cmd" - dirsBinaryLocation = "test/dirs/cmd/testmodule.wasm" - dirsBinaryCmd = "test/dirs/cmd" - httpBinaryLocation = "test/http/cmd/testmodule.wasm" - httpBinaryCmd = "test/http/cmd" - envBinaryLocation = "test/env/cmd/testmodule.wasm" - envBinaryCmd = "test/env/cmd" - logBinaryLocation = "test/log/cmd/testmodule.wasm" - logBinaryCmd = "test/log/cmd" - fetchBinaryLocation = "test/fetch/cmd/testmodule.wasm" - fetchBinaryCmd = "test/fetch/cmd" - fetchlimitBinaryLocation = "test/fetchlimit/cmd/testmodule.wasm" - fetchlimitBinaryCmd = "test/fetchlimit/cmd" - randBinaryLocation = "test/rand/cmd/testmodule.wasm" - randBinaryCmd = "test/rand/cmd" - emitBinaryLocation = "test/emit/cmd/testmodule.wasm" - emitBinaryCmd = "test/emit/cmd" + successBinaryLocation = "test/success/cmd/testmodule.wasm" + successBinaryCmd = "test/success/cmd" + failureBinaryLocation = "test/fail/cmd/testmodule.wasm" + failureBinaryCmd = "test/fail/cmd" + oomBinaryLocation = "test/oom/cmd/testmodule.wasm" + oomBinaryCmd = "test/oom/cmd" + sleepBinaryLocation = "test/sleep/cmd/testmodule.wasm" + sleepBinaryCmd = "test/sleep/cmd" + filesBinaryLocation = "test/files/cmd/testmodule.wasm" + filesBinaryCmd = "test/files/cmd" + dirsBinaryLocation = "test/dirs/cmd/testmodule.wasm" + dirsBinaryCmd = "test/dirs/cmd" + httpBinaryLocation = "test/http/cmd/testmodule.wasm" + httpBinaryCmd = "test/http/cmd" + envBinaryLocation = "test/env/cmd/testmodule.wasm" + envBinaryCmd = "test/env/cmd" + logBinaryLocation = "test/log/cmd/testmodule.wasm" + logBinaryCmd = "test/log/cmd" + fetchBinaryLocation = "test/fetch/cmd/testmodule.wasm" + fetchBinaryCmd = "test/fetch/cmd" + fetchlimitBinaryLocation = "test/fetchlimit/cmd/testmodule.wasm" + fetchlimitBinaryCmd = "test/fetchlimit/cmd" + randBinaryLocation = "test/rand/cmd/testmodule.wasm" + randBinaryCmd = "test/rand/cmd" + emitBinaryLocation = "test/emit/cmd/testmodule.wasm" + emitBinaryCmd = "test/emit/cmd" + computePanicBinaryLocation = "test/computepanic/cmd/testmodule.wasm" + computePanicBinaryCmd = "test/computepanic/cmd" + buildErrorBinaryLocation = "test/builderr/cmd/testmodule.wasm" + buildErrorBinaryCmd = "test/builderr/cmd" ) func createTestBinary(outputPath, path string, uncompressed bool, t *testing.T) []byte { @@ -87,7 +91,7 @@ func Test_GetWorkflowSpec(t *testing.T) { ctx := tests.Context(t) binary := createTestBinary(successBinaryCmd, successBinaryLocation, true, t) - spec, err := GetWorkflowSpec( + _, err := GetWorkflowSpec( ctx, &ModuleConfig{ Logger: logger.Test(t), @@ -97,9 +101,6 @@ func Test_GetWorkflowSpec(t *testing.T) { []byte(""), ) require.NoError(t, err) - - assert.Equal(t, spec.Name, "tester") - assert.Equal(t, spec.Owner, "ryan") } func Test_GetWorkflowSpec_UncompressedBinary(t *testing.T) { @@ -107,7 +108,7 @@ func Test_GetWorkflowSpec_UncompressedBinary(t *testing.T) { ctx := tests.Context(t) binary := createTestBinary(successBinaryCmd, successBinaryLocation, false, t) - spec, err := GetWorkflowSpec( + _, err := GetWorkflowSpec( ctx, &ModuleConfig{ Logger: logger.Test(t), @@ -117,9 +118,6 @@ func Test_GetWorkflowSpec_UncompressedBinary(t *testing.T) { []byte(""), ) require.NoError(t, err) - - assert.Equal(t, spec.Name, "tester") - assert.Equal(t, spec.Owner, "ryan") } func Test_GetWorkflowSpec_BinaryErrors(t *testing.T) { @@ -159,6 +157,23 @@ func Test_GetWorkflowSpec_Timeout(t *testing.T) { assert.ErrorContains(t, err, "wasm trap: interrupt") } +func Test_GetWorkflowSpec_BuildError(t *testing.T) { + t.Parallel() + ctx := tests.Context(t) + binary := createTestBinary(buildErrorBinaryCmd, buildErrorBinaryLocation, true, t) + + _, err := GetWorkflowSpec( + ctx, + &ModuleConfig{ + Logger: logger.Test(t), + IsUncompressed: true, + }, + binary, + []byte(""), + ) + assert.ErrorContains(t, err, "oops") +} + func Test_Compute_Logs(t *testing.T) { t.Parallel() ctx := tests.Context(t) @@ -350,6 +365,37 @@ func Test_Compute_Emit(t *testing.T) { }) } +func Test_Compute_PanicIsRecovered(t *testing.T) { + t.Parallel() + binary := createTestBinary(computePanicBinaryCmd, computePanicBinaryLocation, true, t) + + ctx := tests.Context(t) + m, err := NewModule(&ModuleConfig{ + Logger: logger.Test(t), + IsUncompressed: true, + }, binary) + require.NoError(t, err) + + m.Start() + + req := &wasmpb.Request{ + Id: uuid.New().String(), + Message: &wasmpb.Request_ComputeRequest{ + ComputeRequest: &wasmpb.ComputeRequest{ + Request: &capabilitiespb.CapabilityRequest{ + Inputs: &valuespb.Map{}, + Config: &valuespb.Map{}, + Metadata: &capabilitiespb.RequestMetadata{ + ReferenceId: "transform", + }, + }, + }, + }, + } + _, err = m.Run(ctx, req) + assert.ErrorContains(t, err, "invalid memory address or nil pointer dereference") +} + func Test_Compute_Fetch(t *testing.T) { t.Parallel() binary := createTestBinary(fetchBinaryCmd, fetchBinaryLocation, true, t) diff --git a/pkg/workflows/wasm/runner.go b/pkg/workflows/wasm/runner.go index 0d8ab006e..90f93ee2a 100644 --- a/pkg/workflows/wasm/runner.go +++ b/pkg/workflows/wasm/runner.go @@ -33,17 +33,27 @@ type Runner struct { func (r *Runner) Run(factory *sdk.WorkflowSpecFactory) { if r.req == nil { - req, err := r.parseRequest() - if err != nil { - r.sendResponse(errorResponse(unknownID, err)) + success := r.cacheRequest() + if !success { return } - - r.req = req } req := r.req + // We set this up *after* parsing the request, so that we can guarantee + // that we'll have access to the request object. + defer func() { + if err := recover(); err != nil { + asErr, ok := err.(error) + if ok { + r.sendResponse(errorResponse(r.req.Id, asErr)) + } else { + r.sendResponse(errorResponse(r.req.Id, fmt.Errorf("caught panic: %+v", err))) + } + } + }() + resp := &wasmpb.Response{ Id: req.Id, } @@ -72,18 +82,27 @@ func (r *Runner) Run(factory *sdk.WorkflowSpecFactory) { func (r *Runner) Config() []byte { if r.req == nil { - req, err := r.parseRequest() - if err != nil { - r.sendResponse(errorResponse(unknownID, err)) + success := r.cacheRequest() + if !success { return nil } - - r.req = req } return r.req.Config } +func (r *Runner) ExitWithError(err error) { + if r.req == nil { + success := r.cacheRequest() + if !success { + return + } + } + + r.sendResponse(errorResponse(r.req.Id, err)) + return +} + func errorResponse(id string, err error) *wasmpb.Response { return &wasmpb.Response{ Id: id, @@ -91,6 +110,19 @@ func errorResponse(id string, err error) *wasmpb.Response { } } +func (r *Runner) cacheRequest() bool { + if r.req == nil { + req, err := r.parseRequest() + if err != nil { + r.sendResponse(errorResponse(unknownID, err)) + return false + } + + r.req = req + } + return true +} + func (r *Runner) parseRequest() (*wasmpb.Request, error) { // We expect exactly 2 args, i.e. `wasm `, // where is a base64 encoded protobuf message. diff --git a/pkg/workflows/wasm/runner_test.go b/pkg/workflows/wasm/runner_test.go index 24bb44c91..05aacdcda 100644 --- a/pkg/workflows/wasm/runner_test.go +++ b/pkg/workflows/wasm/runner_test.go @@ -3,10 +3,13 @@ package wasm import ( "encoding/base64" "encoding/binary" + "math/big" "testing" + "time" "unsafe" "github.com/google/uuid" + "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -86,83 +89,339 @@ func Test_Runner_Config(t *testing.T) { assert.Nil(t, gotResponse) } -func TestRunner_Run_ExecuteCompute(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "cedric", - }, - ) - - trigger := basictrigger.TriggerConfig{Name: "trigger", Number: 100}.New(workflow) - computeFn := func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (bool, error) { - return true, nil - } - sdk.Compute1( - workflow, - "compute", - sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, - computeFn, - ) - - var gotResponse *wasmpb.Response - responseFn := func(resp *wasmpb.Response) { - gotResponse = resp - } +type ValidStruct struct { + SomeInt int + SomeString string + SomeTime time.Time +} - m, err := values.NewMap(map[string]any{ - "cool_output": "a trigger event", - }) - require.NoError(t, err) +type PrivateFieldStruct struct { + SomeInt int + SomeString string + somePrivateTime time.Time +} - req := capabilities.CapabilityRequest{ - Config: values.EmptyMap(), - Inputs: m, - Metadata: capabilities.RequestMetadata{ - ReferenceID: "compute", +func TestRunner_Run_ExecuteCompute(t *testing.T) { + now := time.Now().UTC() + + cases := []struct { + name string + expectedOutput any + compute func(*sdk.WorkflowSpecFactory, basictrigger.TriggerOutputsCap) + errorString string + }{ + // Success cases + { + name: "valid compute func - bigint", + expectedOutput: big.NewInt(1), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (*big.Int, error) { + return big.NewInt(1), nil + }, + ) + }, + errorString: "", }, - } - reqpb := capabilitiespb.CapabilityRequestToProto(req) - request := &wasmpb.Request{ - Id: uuid.New().String(), - Message: &wasmpb.Request_ComputeRequest{ - ComputeRequest: &wasmpb.ComputeRequest{ - Request: reqpb, + { + name: "valid compute func - bool", + expectedOutput: true, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (bool, error) { + return true, nil + }, + ) }, + errorString: "", }, - } - str, err := marshalRequest(request) - require.NoError(t, err) - runner := &Runner{ - args: []string{"wasm", str}, - sendResponse: responseFn, - sdkFactory: func(cfg *RuntimeConfig, _ ...func(*RuntimeConfig)) *Runtime { - return nil + { + name: "valid compute func - bytes", + expectedOutput: []byte{3}, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) ([]byte, error) { + return []byte{3}, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - decimal", + expectedOutput: decimal.NewFromInt(2), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (decimal.Decimal, error) { + return decimal.NewFromInt(2), nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - float64", + expectedOutput: float64(1.1), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (float64, error) { + return 1.1, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - int", + expectedOutput: int64(1), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (int, error) { + return 1, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - list", + expectedOutput: []interface{}([]interface{}{int64(1), int64(2), int64(3), int64(4)}), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) ([]int, error) { + return []int{1, 2, 3, 4}, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - map", + expectedOutput: map[string]interface{}(map[string]interface{}{"test": int64(1)}), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (map[string]int, error) { + out := map[string]int{"test": 1} + return out, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - deep map", + expectedOutput: map[string]interface{}(map[string]interface{}{"test1": map[string]interface{}{"test2": int64(1)}}), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (map[string]map[string]int, error) { + out := map[string]map[string]int{"test1": {"test2": 1}} + return out, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - string", + expectedOutput: "hiya", + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (string, error) { + return "hiya", nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - struct", + expectedOutput: map[string]interface{}(map[string]interface{}{"SomeInt": int64(3), "SomeString": "hiya", "SomeTime": now}), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (ValidStruct, error) { + return ValidStruct{SomeString: "hiya", SomeTime: now, SomeInt: 3}, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - empty interface", + expectedOutput: nil, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (interface{}, error) { + var empty interface{} + return empty, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - time", + expectedOutput: now, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (time.Time, error) { + return now, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - any", + expectedOutput: now, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (any, error) { + return now, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - nil", + expectedOutput: nil, + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (any, error) { + return nil, nil + }, + ) + }, + errorString: "", + }, + { + name: "valid compute func - private struct", + expectedOutput: map[string]interface{}(map[string]interface{}{"SomeInt": int64(3), "SomeString": "hiya"}), + compute: func(workflow *sdk.WorkflowSpecFactory, trigger basictrigger.TriggerOutputsCap) { + sdk.Compute1( + workflow, + "compute", + sdk.Compute1Inputs[basictrigger.TriggerOutputs]{Arg0: trigger}, + func(sdk sdk.Runtime, outputs basictrigger.TriggerOutputs) (PrivateFieldStruct, error) { + return PrivateFieldStruct{SomeString: "hiya", somePrivateTime: now, SomeInt: 3}, nil + }, + ) + }, + errorString: "", }, } - runner.Run(workflow) + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + workflow := sdk.NewWorkflowSpecFactory() - assert.NotNil(t, gotResponse.GetComputeResponse()) + trigger := basictrigger.TriggerConfig{Name: "trigger", Number: 100}.New(workflow) - resp := gotResponse.GetComputeResponse().GetResponse() - assert.Equal(t, resp.Error, "") + tt.compute(workflow, trigger) - m, err = values.FromMapValueProto(resp.Value) - require.NoError(t, err) + var gotResponse *wasmpb.Response + responseFn := func(resp *wasmpb.Response) { + gotResponse = resp + } - unw, err := values.Unwrap(m) - require.NoError(t, err) + m, err := values.NewMap(map[string]any{ + "cool_output": "a trigger event", + }) + require.NoError(t, err) + + req := capabilities.CapabilityRequest{ + Config: values.EmptyMap(), + Inputs: m, + Metadata: capabilities.RequestMetadata{ + ReferenceID: "compute", + }, + } + reqpb := capabilitiespb.CapabilityRequestToProto(req) + request := &wasmpb.Request{ + Id: uuid.New().String(), + Message: &wasmpb.Request_ComputeRequest{ + ComputeRequest: &wasmpb.ComputeRequest{ + Request: reqpb, + }, + }, + } + str, err := marshalRequest(request) + require.NoError(t, err) + runner := &Runner{ + args: []string{"wasm", str}, + sendResponse: responseFn, + sdkFactory: func(cfg *RuntimeConfig, _ ...func(*RuntimeConfig)) *Runtime { + return nil + }, + } + runner.Run(workflow) + + if tt.errorString == "" { + assert.NotNil(t, gotResponse.GetComputeResponse()) + resp := gotResponse.GetComputeResponse().GetResponse() + assert.Equal(t, resp.Error, "") + + m, err = values.FromMapValueProto(resp.Value) + require.NoError(t, err) - assert.Equal(t, unw.(map[string]any)["Value"].(bool), true) + unw, err := values.Unwrap(m) + require.NoError(t, err) + + assert.Equal(t, tt.expectedOutput, unw.(map[string]any)["Value"]) + } else { + assert.Equal(t, tt.errorString, gotResponse.ErrMsg) + assert.Nil(t, gotResponse.GetComputeResponse()) + } + }) + } } func TestRunner_Run_GetWorkflowSpec(t *testing.T) { - workflow := sdk.NewWorkflowSpecFactory( - sdk.NewWorkflowParams{ - Name: "tester", - Owner: "cedric", - }, - ) + workflow := sdk.NewWorkflowSpecFactory() trigger := basictrigger.TriggerConfig{Name: "trigger", Number: 100}.New(workflow) // Define and add a target to the workflow