Skip to content

Commit

Permalink
feat(rln-relay): isReady
Browse files Browse the repository at this point in the history
  • Loading branch information
richard-ramos committed Sep 14, 2023
1 parent 7beaa3f commit c3738e9
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 14 deletions.
48 changes: 48 additions & 0 deletions cmd/waku/server/rest/health.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package rest

import (
"context"
"errors"
"net/http"

"github.com/go-chi/chi/v5"
"github.com/waku-org/go-waku/waku/v2/node"
)

type HealthService struct {
node *node.WakuNode
mux *chi.Mux
}

const routeHealth = "/health"

func NewHealthService(node *node.WakuNode, m *chi.Mux) *HealthService {
h := &HealthService{
node: node,
mux: m,
}

m.Get(routeHealth, h.getHealth)

return h
}

type HealthResponse string

func (d *HealthService) getHealth(w http.ResponseWriter, r *http.Request) {
isReady, err := d.node.RLNRelay().IsReady(r.Context())
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
writeResponse(w, HealthResponse("Health check timed out"), http.StatusInternalServerError)
} else {
writeResponse(w, HealthResponse(err.Error()), http.StatusInternalServerError)
}
return
}

if isReady {
writeResponse(w, HealthResponse("Node is healthy"), http.StatusOK)
} else {
writeResponse(w, HealthResponse("Node is not ready"), http.StatusInternalServerError)
}
}
41 changes: 41 additions & 0 deletions cmd/waku/server/rest/health_api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
openapi: 3.0.3
info:
title: Waku V2 node REST API
version: 1.0.0
contact:
name: VAC Team
url: https://forum.vac.dev/

tags:
- name: health
description: Healt check REST API for WakuV2 node

paths:
/health:
get:
summary: Get node health status
description: Retrieve readiness of a Waku v2 node.
operationId: healthcheck
tags:
- health
responses:
'200':
description: Waku v2 node is up and running.
content:
text/plain:
schema:
type: string
example: Node is healty
'500':
description: Internal server error
content:
text/plain:
schema:
type: string
'503':
description: Node not initialized or having issues
content:
text/plain:
schema:
type: string
example: Node is not initialized
2 changes: 1 addition & 1 deletion cmd/waku/server/rest/waku_rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewWakuRest(node *node.WakuNode, address string, port int, enablePProf bool
}

_ = NewDebugService(node, mux)

_ = NewHealthService(node, mux)
_ = NewStoreService(node, mux)

listenAddr := fmt.Sprintf("%s:%d", address, port)
Expand Down
1 change: 1 addition & 0 deletions waku/v2/node/wakunode2.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type RLNRelay interface {
Validator(spamHandler SpamHandler) func(ctx context.Context, message *pb.WakuMessage, topic string) bool
Start(ctx context.Context) error
Stop() error
IsReady(ctx context.Context) (bool, error)
}

type WakuNode struct {
Expand Down
35 changes: 31 additions & 4 deletions waku/v2/protocol/rln/group_manager/dynamic/dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"math/big"
"sync"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -36,14 +37,18 @@ type DynamicGroupManager struct {
identityCredential *rln.IdentityCredential
membershipIndex rln.MembershipIndex

lastBlockProcessed uint64
lastBlockProcessedMutex sync.RWMutex
lastBlockProcessed uint64

appKeystore *keystore.AppKeystore
keystorePassword string
membershipIndexToLoad *uint
}

func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered) error {
gm.lastBlockProcessedMutex.Lock()
defer gm.lastBlockProcessedMutex.Unlock()

toRemoveTable := om.New()
toInsertTable := om.New()

Expand Down Expand Up @@ -82,8 +87,6 @@ func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered)
return err
}

gm.metrics.RecordRegisteredMembership(toInsertTable.Len() - toRemoveTable.Len())

gm.lastBlockProcessed = lastBlockProcessed
err = gm.SetMetadata(RLNMetadata{
LastProcessedBlock: gm.lastBlockProcessed,
Expand All @@ -95,7 +98,7 @@ func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered)
// this is not a fatal error, hence we don't raise an exception
gm.log.Warn("failed to persist rln metadata", zap.Error(err))
} else {
gm.log.Debug("rln metadata persisted", zap.Uint64("lastProcessedBlock", gm.lastBlockProcessed), zap.Uint64("chainID", gm.web3Config.ChainID.Uint64()), logging.HexBytes("contractAddress", gm.web3Config.RegistryContract.Address.Bytes()))
gm.log.Debug("rln metadata persisted", zap.Uint64("lastBlockProcessed", gm.lastBlockProcessed), zap.Uint64("chainID", gm.web3Config.ChainID.Uint64()), logging.HexBytes("contractAddress", gm.web3Config.RegistryContract.Address.Bytes()))
}

return nil
Expand Down Expand Up @@ -228,6 +231,8 @@ func (gm *DynamicGroupManager) InsertMembers(toInsert *om.OrderedMap) error {
}
gm.metrics.RecordMembershipInsertionDuration(time.Since(start))

gm.metrics.RecordRegisteredMembership(startIndex + uint(len(idCommitments)))

_, err = gm.rootTracker.UpdateLatestRoot(pair.Key.(uint64))
if err != nil {
return err
Expand Down Expand Up @@ -279,3 +284,25 @@ func (gm *DynamicGroupManager) Stop() error {

return nil
}

func (gm *DynamicGroupManager) IsReady(ctx context.Context) (bool, error) {
latestBlockNumber, err := gm.latestBlockNumber(ctx)
if err != nil {
return false, fmt.Errorf("could not retrieve latest block: %w", err)
}

gm.lastBlockProcessedMutex.RLock()
allBlocksProcessed := gm.lastBlockProcessed >= latestBlockNumber
gm.lastBlockProcessedMutex.RUnlock()

if !allBlocksProcessed {
return false, nil
}

syncProgress, err := gm.web3Config.ETHClient.SyncProgress(ctx)
if err != nil {
return false, fmt.Errorf("could not retrieve sync state: %w", err)
}

return syncProgress == nil, nil // syncProgress only has a value while node is syncing
}
14 changes: 5 additions & 9 deletions waku/v2/protocol/rln/group_manager/dynamic/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
)

var numberRegisteredMemberships = prometheus.NewCounter(
prometheus.CounterOpts{
var numberRegisteredMemberships = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "waku_rln_number_registered_memberships",
Help: "number of registered and active rln memberships",
})
Expand All @@ -33,7 +33,7 @@ var collectors = []prometheus.Collector{

// Metrics exposes the functions required to update prometheus metrics for lightpush protocol
type Metrics interface {
RecordRegisteredMembership(num int)
RecordRegisteredMembership(num uint)
RecordMembershipInsertionDuration(duration time.Duration)
RecordMembershipCredentialsImportDuration(duration time.Duration)
}
Expand All @@ -60,10 +60,6 @@ func (m *metricsImpl) RecordMembershipCredentialsImportDuration(duration time.Du
}

// RecordRegisteredMembership records the number of registered memberships
func (m *metricsImpl) RecordRegisteredMembership(num int) {
if num < 0 {
return
}

numberRegisteredMemberships.Add(float64(num))
func (m *metricsImpl) RecordRegisteredMembership(num uint) {
numberRegisteredMemberships.Set(float64(num))
}
1 change: 1 addition & 0 deletions waku/v2/protocol/rln/group_manager/group_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type GroupManager interface {
IdentityCredentials() (rln.IdentityCredential, error)
MembershipIndex() rln.MembershipIndex
Stop() error
IsReady(ctx context.Context) (bool, error)
}

type Details struct {
Expand Down
4 changes: 4 additions & 0 deletions waku/v2/protocol/rln/group_manager/static/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ func (gm *StaticGroupManager) Stop() error {
// Do nothing
return nil
}

func (gm *StaticGroupManager) IsReady(ctx context.Context) (bool, error) {
return true, nil
}
5 changes: 5 additions & 0 deletions waku/v2/protocol/rln/waku_rln_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,8 @@ func (rlnRelay *WakuRLNRelay) IdentityCredential() (rln.IdentityCredential, erro
func (rlnRelay *WakuRLNRelay) MembershipIndex() uint {
return rlnRelay.GroupManager.MembershipIndex()
}

// IsReady returns true if the RLN Relay protocol is ready to relay messages
func (rlnRelay *WakuRLNRelay) IsReady(ctx context.Context) (bool, error) {
return rlnRelay.GroupManager.IsReady(ctx)
}
1 change: 1 addition & 0 deletions waku/v2/protocol/rln/web3/web3.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type RLNContract struct {
// EthClient is an interface for the ethclient.Client, so that we can pass mock client for testing
type EthClient interface {
bind.ContractBackend
SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error)
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error)
Expand Down

0 comments on commit c3738e9

Please sign in to comment.