@@ -2,11 +2,18 @@ package task
22
33import (
44 "context"
5+ "errors"
6+ "fmt"
7+ "sync"
58
9+ "github.com/LumeraProtocol/supernode/pkg/errgroup"
10+ "github.com/LumeraProtocol/supernode/pkg/logtrace"
611 "github.com/LumeraProtocol/supernode/sdk/adapters/lumera"
712 "github.com/LumeraProtocol/supernode/sdk/config"
813 "github.com/LumeraProtocol/supernode/sdk/event"
914 "github.com/LumeraProtocol/supernode/sdk/log"
15+ "github.com/LumeraProtocol/supernode/sdk/net"
16+ "google.golang.org/grpc/health/grpc_health_v1"
1017
1118 "github.com/cosmos/cosmos-sdk/crypto/keyring"
1219)
@@ -67,3 +74,63 @@ func (t *BaseTask) LogEvent(ctx context.Context, evt event.EventType, msg string
6774 t .logger .Info (ctx , msg , kvs ... )
6875 t .emitEvent (ctx , evt , additionalInfo )
6976}
77+
78+ func (t * BaseTask ) fetchSupernodes (ctx context.Context , height int64 ) (lumera.Supernodes , error ) {
79+ sns , err := t .client .GetSupernodes (ctx , height )
80+ if err != nil {
81+ return nil , fmt .Errorf ("fetch supernodes: %w" , err )
82+ }
83+
84+ if len (sns ) == 0 {
85+ return nil , errors .New ("no supernodes found" )
86+ }
87+
88+ if len (sns ) > 10 {
89+ sns = sns [:10 ]
90+ }
91+
92+ // Keep only SERVING nodes (done in parallel – keeps latency flat)
93+ healthy := make (lumera.Supernodes , 0 , len (sns ))
94+ eg , ctx := errgroup .WithContext (ctx )
95+ mu := sync.Mutex {}
96+
97+ for _ , sn := range sns {
98+ sn := sn
99+ eg .Go (func () error {
100+ if t .isServing (ctx , sn ) {
101+ mu .Lock ()
102+ healthy = append (healthy , sn )
103+ mu .Unlock ()
104+ }
105+ return nil
106+ })
107+ }
108+ if err := eg .Wait (); err != nil {
109+ return nil , fmt .Errorf ("health-check goroutines: %w" , err )
110+ }
111+
112+ if len (healthy ) == 0 {
113+ return nil , errors .New ("no healthy supernodes found" )
114+ }
115+
116+ return healthy , nil
117+ }
118+
119+ // isServing pings the super-node once with a short timeout.
120+ func (t * BaseTask ) isServing (parent context.Context , sn lumera.Supernode ) bool {
121+ ctx , cancel := context .WithTimeout (parent , connectionTimeout )
122+ defer cancel ()
123+
124+ client , err := net .NewClientFactory (ctx , t .logger , t .keyring , t .client , net.FactoryConfig {
125+ LocalCosmosAddress : t .config .Account .LocalCosmosAddress ,
126+ PeerType : t .config .Account .PeerType ,
127+ }).CreateClient (ctx , sn )
128+ if err != nil {
129+ logtrace .Info (ctx , "Failed to create client for supernode" , logtrace.Fields {logtrace .FieldMethod : "isServing" })
130+ return false
131+ }
132+ defer client .Close (ctx )
133+
134+ resp , err := client .HealthCheck (ctx )
135+ return err == nil && resp .Status == grpc_health_v1 .HealthCheckResponse_SERVING
136+ }
0 commit comments