@@ -19,6 +19,9 @@ package rpc
1919import (
2020 "context"
2121 "net/rpc"
22+ "sync"
23+ "math/rand"
24+ "errors"
2225
2326 "github.com/hashicorp/yamux"
2427 "gitlab.com/thunderdb/ThunderDB/crypto/kms"
@@ -27,6 +30,16 @@ import (
2730 "gitlab.com/thunderdb/ThunderDB/utils/log"
2831)
2932
33+ var (
34+ // ErrNoChiefBlockProducerAvailable defines failure on find chief block producer.
35+ ErrNoChiefBlockProducerAvailable = errors .New ("no chief block producer found" )
36+
37+ // currentBP represents current chief block producer node.
38+ currentBP proto.NodeID
39+ // currentBPLock represents the chief block producer access lock.
40+ currentBPLock sync.Mutex
41+ )
42+
3043// Caller is a wrapper for session pooling and RPC calling.
3144type Caller struct {
3245 pool * SessionPool
@@ -84,7 +97,7 @@ func (c *Caller) CallNodeWithContext(
8497 return
8598}
8699
87- // GetNodeAddr tries best to get node addr
100+ // GetNodeAddr tries best to get node addr.
88101func GetNodeAddr (id * proto.RawNodeID ) (addr string , err error ) {
89102 addr , err = route .GetNodeAddrCache (id )
90103 if err != nil {
@@ -120,7 +133,7 @@ func GetNodeAddr(id *proto.RawNodeID) (addr string, err error) {
120133 return
121134}
122135
123- // GetNodeInfo tries best to get node info
136+ // GetNodeInfo tries best to get node info.
124137func GetNodeInfo (id * proto.RawNodeID ) (nodeInfo * proto.Node , err error ) {
125138 nodeInfo , err = kms .GetNodeInfo (proto .NodeID (id .String ()))
126139 if err != nil {
@@ -163,7 +176,7 @@ func GetNodeInfo(id *proto.RawNodeID) (nodeInfo *proto.Node, err error) {
163176 return
164177}
165178
166- // PingBP Send DHT.Ping Request with Anonymous ETLS session
179+ // PingBP Send DHT.Ping Request with Anonymous ETLS session.
167180func PingBP (node * proto.Node , BPNodeID proto.NodeID ) (err error ) {
168181 client := NewCaller ()
169182
@@ -181,3 +194,64 @@ func PingBP(node *proto.Node, BPNodeID proto.NodeID) (err error) {
181194
182195 return
183196}
197+
198+ // GetCurrentBP returns nearest hash distance block producer as current node chief block producer.
199+ func GetCurrentBP () (bpNodeID proto.NodeID , err error ) {
200+ currentBPLock .Lock ()
201+ defer currentBPLock .Unlock ()
202+
203+ if ! currentBP .IsEmpty () {
204+ bpNodeID = currentBP
205+ return
206+ }
207+
208+ var localNodeID proto.NodeID
209+ if localNodeID , err = kms .GetLocalNodeID (); err != nil {
210+ return
211+ }
212+
213+ // get random block producer first
214+ bpList := route .GetBPs ()
215+ randomBP := bpList [rand .Intn (len (bpList ))]
216+
217+ // call random block producer for nearest block producer node
218+ req := & proto.FindNeighborReq {
219+ NodeID : localNodeID ,
220+ Roles : []proto.ServerRole {
221+ proto .Leader ,
222+ proto .Follower ,
223+ },
224+ Count : 1 ,
225+ }
226+ res := new (proto.FindNeighborResp )
227+ if err = NewCaller ().CallNode (randomBP , "DHT.FindNeighbor" , req , res ); err != nil {
228+ return
229+ }
230+
231+ if len (res .Nodes ) <= 0 {
232+ // node not found
233+ err = ErrNoChiefBlockProducerAvailable
234+ return
235+ }
236+
237+ if res .Nodes [0 ].Role != proto .Leader && res .Nodes [0 ].Role != proto .Follower {
238+ // not block producer
239+ err = ErrNoChiefBlockProducerAvailable
240+ return
241+ }
242+
243+ currentBP = res .Nodes [0 ].ID
244+ bpNodeID = currentBP
245+
246+ return
247+ }
248+
249+ // SetCurrentBP sets current node chief block producer.
250+ func SetCurrentBP (bpNodeID proto.NodeID ) {
251+ currentBPLock .Lock ()
252+ defer currentBPLock .Unlock ()
253+
254+ currentBP = bpNodeID
255+
256+ return
257+ }
0 commit comments