Skip to content

Commit

Permalink
Implement get active validators
Browse files Browse the repository at this point in the history
  • Loading branch information
pablomendezroyo committed Apr 12, 2024
1 parent 8ac48ea commit d7d171e
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 21 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ MONGO_DB_NAME=
MONGO_DB_API_PORT=
API_PORT=
LOG_LEVEL=
BEACON_NODE_URL=
1 change: 1 addition & 0 deletions listener/cmd/listener/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func main() {
s := api.NewApi(
config.Port,
config.MongoDBURI,
config.BeaconNodeURL,
)

s.Start()
Expand Down
16 changes: 9 additions & 7 deletions listener/internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ import (
)

type httpApi struct {
server *http.Server
port string
dbUri string
server *http.Server
port string
dbUri string
beaconNodeUrl string
}

// create a new api instance
func NewApi(port string, mongoDbUri string) *httpApi {
func NewApi(port string, mongoDbUri string, beaconNodeUrl string) *httpApi {
return &httpApi{
port: port,
dbUri: mongoDbUri,
port: port,
dbUri: mongoDbUri,
beaconNodeUrl: beaconNodeUrl,
}
}

Expand Down Expand Up @@ -47,7 +49,7 @@ func (s *httpApi) Start() {
// setup the http api
s.server = &http.Server{
Addr: ":" + s.port,
Handler: routes.SetupRouter(dbCollection),
Handler: routes.SetupRouter(dbCollection, s.beaconNodeUrl),
}

// start the api
Expand Down
4 changes: 2 additions & 2 deletions listener/internal/api/handlers/postNewSignature.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func validateAndInsertSignature(req types.SignatureRequestDecoded, dbCollection
// 1. Decode and validate
// 2. Get active validators
// 3. Validate signature and insert into MongoDB
func PostNewSignature(w http.ResponseWriter, r *http.Request, dbCollection *mongo.Collection) {
func PostNewSignature(w http.ResponseWriter, r *http.Request, dbCollection *mongo.Collection, beaconNodeUrl string) {
logger.Debug("Received new POST '/newSignature' request")

// Decode and validate incoming requests
Expand All @@ -117,7 +117,7 @@ func PostNewSignature(w http.ResponseWriter, r *http.Request, dbCollection *mong
}

// Get active validators
requestsWithActiveValidators, err := validation.GetActiveValidators(validRequests)
requestsWithActiveValidators, err := validation.GetActiveValidators(validRequests, beaconNodeUrl)
if err != nil {
respondError(w, http.StatusInternalServerError, "Failed to validate active validators")
return
Expand Down
4 changes: 2 additions & 2 deletions listener/internal/api/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import (
"go.mongodb.org/mongo-driver/mongo"
)

func SetupRouter(dbCollection *mongo.Collection) *mux.Router {
func SetupRouter(dbCollection *mongo.Collection, beaconNodeUrl string) *mux.Router {
r := mux.NewRouter()

// Define routes
r.HandleFunc("/", handlers.GetHealthCheck).Methods(http.MethodGet)
// closure function to inject dbCollection into the handler
r.HandleFunc("/newSignature", func(w http.ResponseWriter, r *http.Request) {
handlers.PostNewSignature(w, r, dbCollection)
handlers.PostNewSignature(w, r, dbCollection, beaconNodeUrl)
}).Methods(http.MethodPost)
r.HandleFunc("/signaturesByValidator", func(w http.ResponseWriter, r *http.Request) {
handlers.PostSignaturesByValidator(w, r, dbCollection)
Expand Down
67 changes: 60 additions & 7 deletions listener/internal/api/validation/GetActiveValidators.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,65 @@
package validation

import "github.com/dappnode/validator-monitoring/listener/internal/api/types"
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"

// ValidatePubkeysWithConsensusClient checks if the given pubkeys from the requests are from active validators
// or not by making SINGLE API call to the consensus client. It returns an array of the active validators pubkeys.
func GetActiveValidators(requestsDecoded []types.SignatureRequestDecoded) ([]types.SignatureRequestDecoded, error) {
requestsActiveValidators := requestsDecoded
// make api call: GET /eth/v1/beacon/states/{state_id}/validators?id=validator_pubkey1,validator_pubkey2,validator_pubkey3
"github.com/dappnode/validator-monitoring/listener/internal/api/types"
)

return requestsActiveValidators, nil
func GetActiveValidators(requestsDecoded []types.SignatureRequestDecoded, beaconNodeUrl string) ([]types.SignatureRequestDecoded, error) {
if len(requestsDecoded) == 0 {
return nil, fmt.Errorf("no validators to check")
}

// Prepare the request body
ids := make([]string, 0, len(requestsDecoded))
for _, req := range requestsDecoded {
ids = append(ids, req.DecodedPayload.Pubkey)
}
requestBody := struct {
Ids []string `json:"ids"`
Statuses []string `json:"statuses"`
}{
Ids: ids,
Statuses: []string{"active_ongoing"},
}

// Serialize the request body to JSON
jsonData, err := json.Marshal(requestBody)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}

// Configure HTTP client with timeout
client := &http.Client{Timeout: 10 * time.Second}
url := fmt.Sprintf("%s/eth/v1/beacon/states/head/validators", beaconNodeUrl)
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("error making API call to %s: %w", url, err)
}
defer resp.Body.Close()

// Check the HTTP response status before reading the body
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API call to %s returned status %d", url, resp.StatusCode)
}

// Read and log the response body
responseData, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response data: %w", err)
}

// Assuming the server returns a list of active validators in the format you expect
var activeValidators []types.SignatureRequestDecoded
if err := json.Unmarshal(responseData, &activeValidators); err != nil {
return nil, fmt.Errorf("error unmarshaling response data: %w", err)
}

return activeValidators, nil
}
Empty file.
14 changes: 11 additions & 3 deletions listener/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type Config struct {
MongoDBURI string
// LogLevel is the level of logging
LogLevel string
// BeaconNodeURL is the URL of the beacon node
BeaconNodeURL string
}

func LoadConfig() (*Config, error) {
Expand All @@ -34,9 +36,15 @@ func LoadConfig() (*Config, error) {
logger.Fatal("API_PORT is not set")
}

beaconNodeURL := os.Getenv("BEACON_NODE_URL")
if beaconNodeURL == "" {
logger.Fatal("BEACON_NODE_URL is not set")
}

return &Config{
Port: apiPort,
MongoDBURI: mongoDBURI,
LogLevel: logLevel,
Port: apiPort,
MongoDBURI: mongoDBURI,
LogLevel: logLevel,
BeaconNodeURL: beaconNodeURL,
}, nil
}

0 comments on commit d7d171e

Please sign in to comment.