Skip to content

Commit 8164a8f

Browse files
JulianVenturaJuArceavilagaston9Julian VenturaOppen
authored
feat(telemetry): Add url data to operator updates on telemetry service (#1136)
Co-authored-by: JuArce <[email protected]> Co-authored-by: Avila Gastón <[email protected]> Co-authored-by: Julian Ventura <[email protected]> Co-authored-by: avilagaston9 <[email protected]> Co-authored-by: Mario Rugiero <[email protected]>
1 parent 7671be6 commit 8164a8f

File tree

10 files changed

+191
-54
lines changed

10 files changed

+191
-54
lines changed

core/config/base.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type BaseConfig struct {
3333
EthRpcClientFallback eth.InstrumentedClient
3434
EthWsClient eth.InstrumentedClient
3535
EthWsClientFallback eth.InstrumentedClient
36+
EthRpcUrlFallback string
37+
EthWsUrlFallback string
3638
EigenMetricsIpPortAddress string
3739
ChainId *big.Int
3840
}
@@ -149,6 +151,8 @@ func NewBaseConfig(configFilePath string) *BaseConfig {
149151
EthRpcClientFallback: *ethRpcClientFallback,
150152
EthWsClient: *ethWsClient,
151153
EthWsClientFallback: *ethWsClientFallback,
154+
EthRpcUrlFallback: baseConfigFromYaml.EthRpcUrlFallback,
155+
EthWsUrlFallback: baseConfigFromYaml.EthWsUrlFallback,
152156
EigenMetricsIpPortAddress: baseConfigFromYaml.EigenMetricsIpPortAddress,
153157
ChainId: chainId,
154158
}

operator/cmd/actions/start.go

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package actions
22

33
import (
4-
"bytes"
54
"context"
6-
"encoding/json"
75
"log"
8-
"net/http"
96

107
sdkutils "github.com/Layr-Labs/eigensdk-go/utils"
11-
"github.com/ethereum/go-ethereum/crypto"
128
"github.com/urfave/cli/v2"
139
"github.com/yetanotherco/aligned_layer/core/config"
1410
operator "github.com/yetanotherco/aligned_layer/operator/pkg"
15-
"golang.org/x/crypto/sha3"
1611
)
1712

1813
var StartFlags = []cli.Flag{
@@ -39,44 +34,11 @@ func operatorMain(ctx *cli.Context) error {
3934
return err
4035
}
4136

42-
// hash version
43-
hash := sha3.NewLegacyKeccak256()
44-
hash.Write([]byte(ctx.App.Version))
45-
46-
// get hash
47-
version := hash.Sum(nil)
48-
49-
// sign version
50-
signature, err := crypto.Sign(version[:], operatorConfig.EcdsaConfig.PrivateKey)
51-
if err != nil {
52-
return err
53-
}
54-
55-
body := map[string]interface{}{
56-
"version": ctx.App.Version,
57-
"signature": signature,
58-
}
59-
bodyBuffer := new(bytes.Buffer)
60-
61-
bodyReader := json.NewEncoder(bodyBuffer)
62-
err = bodyReader.Encode(body)
37+
err = operator.SendTelemetryData(ctx)
6338
if err != nil {
6439
return err
6540
}
6641

67-
// send version to operator tracker server
68-
endpoint := operatorConfig.Operator.OperatorTrackerIpPortAddress + "/versions"
69-
operator.Logger.Info("Sending version to operator tracker server: ", "endpoint", endpoint)
70-
71-
res, err := http.Post(endpoint, "application/json",
72-
bodyBuffer)
73-
if err != nil {
74-
// Dont prevent operator from starting if operator tracker server is down
75-
operator.Logger.Warn("Error sending version to metrics server: ", "err", err)
76-
} else if res.StatusCode != http.StatusCreated && res.StatusCode != http.StatusNoContent {
77-
operator.Logger.Warn("Error sending version to operator tracker server: ", "status_code", res.StatusCode)
78-
}
79-
8042
operator.Logger.Info("Operator starting...")
8143
err = operator.Start(context.Background())
8244
if err != nil {

operator/pkg/operator.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import (
88
"encoding/json"
99
"fmt"
1010
"log"
11+
"net/http"
1112
"os"
1213
"path/filepath"
1314
"sync"
1415
"time"
1516

1617
"github.com/ethereum/go-ethereum/crypto"
18+
"github.com/urfave/cli/v2"
1719
"github.com/yetanotherco/aligned_layer/operator/risc_zero"
20+
"golang.org/x/crypto/sha3"
1821

1922
"github.com/prometheus/client_golang/prometheus"
2023
"github.com/yetanotherco/aligned_layer/metrics"
@@ -590,3 +593,65 @@ func (o *Operator) SignTaskResponse(batchIdentifierHash [32]byte) *bls.Signature
590593
responseSignature := *o.Config.BlsConfig.KeyPair.SignMessage(batchIdentifierHash)
591594
return &responseSignature
592595
}
596+
597+
func (o *Operator) SendTelemetryData(ctx *cli.Context) error {
598+
// hash version
599+
hash := sha3.NewLegacyKeccak256()
600+
hash.Write([]byte(ctx.App.Version))
601+
602+
// get hash
603+
version := hash.Sum(nil)
604+
605+
// sign version
606+
signature, err := crypto.Sign(version[:], o.Config.EcdsaConfig.PrivateKey)
607+
if err != nil {
608+
return err
609+
}
610+
ethRpcUrl, err := BaseUrlOnly(o.Config.BaseConfig.EthRpcUrl)
611+
if err != nil {
612+
return err
613+
}
614+
ethRpcUrlFallback, err := BaseUrlOnly(o.Config.BaseConfig.EthRpcUrlFallback)
615+
if err != nil {
616+
return err
617+
}
618+
ethWsUrl, err := BaseUrlOnly(o.Config.BaseConfig.EthWsUrl)
619+
if err != nil {
620+
return err
621+
}
622+
ethWsUrlFallback, err := BaseUrlOnly(o.Config.BaseConfig.EthWsUrlFallback)
623+
if err != nil {
624+
return err
625+
}
626+
627+
body := map[string]interface{}{
628+
"version": ctx.App.Version,
629+
"signature": signature,
630+
"eth_rpc_url": ethRpcUrl,
631+
"eth_rpc_url_fallback": ethRpcUrlFallback,
632+
"eth_ws_url": ethWsUrl,
633+
"eth_ws_url_fallback": ethWsUrlFallback,
634+
}
635+
636+
bodyBuffer := new(bytes.Buffer)
637+
638+
bodyReader := json.NewEncoder(bodyBuffer)
639+
err = bodyReader.Encode(body)
640+
if err != nil {
641+
return err
642+
}
643+
644+
// send version to operator tracker server
645+
endpoint := o.Config.Operator.OperatorTrackerIpPortAddress + "/versions"
646+
o.Logger.Info("Sending version to operator tracker server: ", "endpoint", endpoint)
647+
648+
res, err := http.Post(endpoint, "application/json", bodyBuffer)
649+
if err != nil {
650+
// Dont prevent operator from starting if operator tracker server is down
651+
o.Logger.Warn("Error sending version to metrics server: ", "err", err)
652+
} else if res.StatusCode != http.StatusCreated && res.StatusCode != http.StatusNoContent {
653+
o.Logger.Warn("Error sending version to operator tracker server: ", "status_code", res.StatusCode)
654+
}
655+
656+
return nil
657+
}

operator/pkg/utils.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package operator
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strings"
7+
)
8+
9+
func BaseUrlOnly(input string) (string, error) {
10+
// Define a regex pattern to match the URL format
11+
// The pattern captures the scheme, host, and path
12+
pattern := `^(?P<scheme>[^:]+)://(?P<host>[^/]+)(?P<path>/.*)?$`
13+
re := regexp.MustCompile(pattern)
14+
15+
matches := re.FindStringSubmatch(input)
16+
17+
if matches == nil {
18+
return "", fmt.Errorf("invalid URL: %s", input)
19+
}
20+
21+
host := matches[2]
22+
path := matches[3]
23+
24+
// If the path is not empty, append the path without the last segment (api_key)
25+
if path != "" {
26+
pathSegments := strings.Split(path, "/")
27+
if len(pathSegments) > 1 {
28+
return host + strings.Join(pathSegments[:len(pathSegments)-1], "/"), nil
29+
}
30+
}
31+
32+
return host, nil
33+
}

operator/pkg/utils_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package operator
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestBaseUrlOnlyHappyPath(t *testing.T) {
8+
// Format "<protocol>://<base_url>/<api_key>"
9+
10+
urls := [...][2]string{
11+
{"http://localhost:8545/asdfoij2a7831has89%342jddav98j2748", "localhost:8545"},
12+
{"ws://test.com/23r2f98hkjva0udhvi1j%342jddav98j2748", "test.com"},
13+
{"http://localhost:8545", "localhost:8545"},
14+
{"https://myservice.com/holesky/ApiKey", "myservice.com/holesky"},
15+
}
16+
17+
for _, pair := range urls {
18+
url := pair[0]
19+
expectedBaseUrl := pair[1]
20+
21+
baseUrl, err := BaseUrlOnly(url)
22+
23+
if err != nil {
24+
t.Errorf("Unexpected error for URL %s: %v", url, err)
25+
}
26+
27+
if baseUrl != expectedBaseUrl {
28+
t.Errorf("Expected base URL %s, got %s for URL %s", expectedBaseUrl, baseUrl, url)
29+
}
30+
}
31+
}
32+
33+
func TestBaseUrlOnlyFailureCases(t *testing.T) {
34+
35+
urls := [...]string{
36+
"localhost:8545/asdfoij2a7831has89%342jddav98j2748",
37+
"this-is-all-wrong",
38+
}
39+
40+
for _, url := range urls {
41+
baseUrl, err := BaseUrlOnly(url)
42+
43+
if err == nil {
44+
t.Errorf("An error was expected, but received %s", baseUrl)
45+
}
46+
}
47+
}

telemetry_api/lib/telemetry_api/operators.ex

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,38 +112,33 @@ defmodule TelemetryApi.Operators do
112112
end
113113

114114
@doc """
115-
Updates an operator's version.
115+
Updates an operator.
116116
117117
## Examples
118118
119-
iex> update_operator_version(%{field: value})
119+
iex> update_operator(some_version, some_signature, %{field: value})
120120
{:ok, %Ecto.Changeset{}}
121121
122-
iex> update_operator_version(%{field: bad_value})
122+
iex> update_operator(some_version, invalid_signature, %{field: value})
123123
{:error, "Some status", "Some message"}
124124
125125
"""
126-
def update_operator_version(%{"version" => version, "signature" => signature}) do
126+
def update_operator(version, signature, changes) do
127127
with {:ok, address} <- SignatureVerifier.recover_address(version, signature) do
128128
address = "0x" <> address
129-
# We only want to allow changes on version
130-
changes = %{
131-
version: version
132-
}
133-
134129
case Repo.get(Operator, address) do
135130
nil ->
136131
{:error, :bad_request,
137132
"Provided address does not correspond to any registered operator"}
138133

139134
operator ->
140-
operator |> Operator.changeset(changes) |> Repo.insert_or_update()
135+
update_operator(operator, changes)
141136
end
142137
end
143138
end
144139

145140
@doc """
146-
Updates a operator.
141+
Updates an operator.
147142
148143
## Examples
149144

telemetry_api/lib/telemetry_api/operators/operator.ex

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,29 @@ defmodule TelemetryApi.Operators.Operator do
99
field :name, :string
1010
field :version, :string
1111
field :status, :string
12+
field :eth_rpc_url, :string
13+
field :eth_rpc_url_fallback, :string
14+
field :eth_ws_url, :string
15+
field :eth_ws_url_fallback, :string
1216

1317
timestamps(type: :utc_datetime)
1418
end
1519

1620
@doc false
1721
def changeset(operator, attrs) do
1822
operator
19-
|> cast(attrs, [:address, :id, :stake, :name, :version, :status])
23+
|> cast(attrs, [
24+
:address,
25+
:id,
26+
:stake,
27+
:name,
28+
:version,
29+
:status,
30+
:eth_rpc_url,
31+
:eth_rpc_url_fallback,
32+
:eth_ws_url,
33+
:eth_ws_url_fallback
34+
])
2035
|> validate_required([:address, :id, :name, :stake])
2136
end
2237
end

telemetry_api/lib/telemetry_api_web/controllers/operator_controller.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ defmodule TelemetryApiWeb.OperatorController do
1111
render(conn, :index, operators: operators)
1212
end
1313

14-
def create_or_update(conn, operator_params) do
15-
with {:ok, %Operator{} = operator} <- Operators.update_operator_version(operator_params) do
14+
def create_or_update(conn, %{"version" => version, "signature" => signature} = attrs) do
15+
with {:ok, %Operator{} = operator} <- Operators.update_operator(version, signature, attrs) do
1616
conn
1717
|> put_status(:created)
1818
|> put_resp_header("location", ~p"/api/operators/#{operator}")

telemetry_api/lib/telemetry_api_web/controllers/operator_json.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ defmodule TelemetryApiWeb.OperatorJSON do
2222
stake: operator.stake,
2323
name: operator.name,
2424
version: operator.version,
25-
status: operator.status
25+
status: operator.status,
26+
eth_rpc_url: operator.eth_rpc_url,
27+
eth_rpc_url_fallback: operator.eth_rpc_url_fallback,
28+
eth_ws_url: operator.eth_ws_url,
29+
eth_ws_url_fallback: operator.eth_ws_url_fallback
2630
}
2731
end
2832
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule TelemetryApi.Repo.Migrations.AddOperatorUrlData do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:operators) do
6+
add :eth_rpc_url, :string
7+
add :eth_rpc_url_fallback, :string
8+
add :eth_ws_url, :string
9+
add :eth_ws_url_fallback, :string
10+
end
11+
end
12+
end

0 commit comments

Comments
 (0)