@@ -50,18 +50,6 @@ type RCManager struct {
5050 subscriberCount int
5151}
5252
53- // subSnapshot returns the current subscription pointer and its cached Info pointer (if any)
54- // under the manager lock. Callers should avoid holding the lock across network calls.
55- func (r * RCManager ) subSnapshot (rootChainId uint64 ) (sub * RCSubscription , info * lib.RootChainInfo , found bool ) {
56- r .l .Lock ()
57- sub , found = r .subscriptions [rootChainId ]
58- if found && sub != nil {
59- info = sub .Info
60- }
61- r .l .Unlock ()
62- return
63- }
64-
6553// NewRCManager() constructs a new instance of a RCManager
6654func NewRCManager (controller * controller.Controller , config lib.Config , logger lib.LoggerI ) (manager * RCManager ) {
6755 readLimit := config .RCSubscriberReadLimitBytes
@@ -148,29 +136,43 @@ func (r *RCManager) Publish(chainId uint64, info *lib.RootChainInfo) {
148136
149137// ChainIds() returns a list of chainIds for subscribers
150138func (r * RCManager ) ChainIds () (list []uint64 ) {
151- r .l .Lock ()
152- for chainId , subs := range r .subscribers {
153- if chainId != 0 && len (subs ) != 0 {
154- list = append (list , chainId )
139+ // de-duplicate the results
140+ deDupe := lib .NewDeDuplicator [uint64 ]()
141+ // for each client
142+ for chainId , chainSubscribers := range r .subscribers {
143+ // if the client chain id isn't empty and not duplicate
144+ for _ , subscriber := range chainSubscribers {
145+ if subscriber .chainId != chainId {
146+ // remove subscriber with incorrect chain id
147+ subscriber .Stop (lib .ErrWrongChainId ())
148+ continue
149+ }
150+ if subscriber .chainId != 0 && ! deDupe .Found (subscriber .chainId ) {
151+ list = append (list , subscriber .chainId )
152+ }
155153 }
156154 }
157- r .l .Unlock ()
158- return list
155+ return
159156}
160157
161158// GetHeight() returns the height from the root-chain
162159func (r * RCManager ) GetHeight (rootChainId uint64 ) uint64 {
163- _ , info , found := r .subSnapshot (rootChainId )
164- if found && info != nil {
165- return info .Height
160+ // check the map to see if the info exists
161+ if sub , found := r .subscriptions [rootChainId ]; found {
162+ // exit with the height of the root-chain-info
163+ return sub .Info .Height
166164 }
167165 return 0
168166}
169167
170168// GetRootChainInfo() retrieves the root chain info from the root chain 'on-demand'
171169func (r * RCManager ) GetRootChainInfo (rootChainId , chainId uint64 ) (info * lib.RootChainInfo , err lib.ErrorI ) {
172170 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
173- sub , _ , found := r .subSnapshot (rootChainId )
171+ // lock for thread safety
172+ r .l .Lock ()
173+ defer r .l .Unlock ()
174+ // if the root chain id is the same as the info
175+ sub , found := r .subscriptions [rootChainId ]
174176 if ! found {
175177 // exit with 'not subscribed' error
176178 return nil , lib .ErrNotSubscribed ()
@@ -180,63 +182,53 @@ func (r *RCManager) GetRootChainInfo(rootChainId, chainId uint64) (info *lib.Roo
180182 if err != nil {
181183 return nil , err
182184 }
183- // update cached info under lock (don't hold the lock during the RPC call above)
184- r .l .Lock ()
185- if cur , ok := r .subscriptions [rootChainId ]; ok && cur == sub {
186- sub .Info = info
187- }
188- r .l .Unlock ()
185+ // update the info
186+ sub .Info = info
189187 // exit with the info
190188 return
191189}
192190
193191// GetValidatorSet() returns the validator set from the root-chain
194192func (r * RCManager ) GetValidatorSet (rootChainId , id , rootHeight uint64 ) (lib.ValidatorSet , lib.ErrorI ) {
195193 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
196- sub , info , found := r .subSnapshot (rootChainId )
194+ // if the root chain id is the same as the info
195+ sub , found := r .subscriptions [rootChainId ]
197196 if ! found {
198197 // exit with 'not subscribed' error
199198 return lib.ValidatorSet {}, lib .ErrNotSubscribed ()
200199 }
201200 // if rootHeight is the same as the RootChainInfo height
202- if info != nil && ( rootHeight == info . Height || rootHeight == 0 ) {
201+ if rootHeight == sub . Info . Height || rootHeight == 0 {
203202 // exit with a copy the validator set
204- return lib .NewValidatorSet (info .ValidatorSet )
203+ return lib .NewValidatorSet (sub . Info .ValidatorSet )
205204 }
206205 // if rootHeight is 1 before the RootChainInfo height
207- if info != nil && info . Height != 0 && rootHeight == info .Height - 1 {
206+ if rootHeight == sub . Info .Height - 1 {
208207 // exit with a copy of the previous validator set
209- return lib .NewValidatorSet (info .LastValidatorSet )
208+ return lib .NewValidatorSet (sub . Info .LastValidatorSet )
210209 }
211210 // warn of the remote RPC call to the root chain API
212- latest := uint64 (0 )
213- if info != nil {
214- latest = info .Height
215- }
216- r .log .Warnf ("Executing remote GetValidatorSet call with requested height=%d for rootChainId=%d with latest root height at %d" , rootHeight , rootChainId , latest )
211+ r .log .Warnf ("Executing remote GetValidatorSet call with requested height=%d for rootChainId=%d with latest root height at %d" , rootHeight , rootChainId , sub .Info .Height )
217212 // execute the remote RPC call to the root chain API
218213 return sub .ValidatorSet (rootHeight , id )
219214}
220215
221216// GetOrders() returns the order book from the root-chain
222217func (r * RCManager ) GetOrders (rootChainId , rootHeight , id uint64 ) (* lib.OrderBook , lib.ErrorI ) {
223218 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
224- sub , info , found := r .subSnapshot (rootChainId )
219+ // if the root chain id is the same as the info
220+ sub , found := r .subscriptions [rootChainId ]
225221 if ! found {
226222 // exit with 'not subscribed' error
227223 return nil , lib .ErrNotSubscribed ()
228224 }
229225 // if the root chain id and height is the same as the info
230- if info != nil && info .Height == rootHeight {
226+ if sub . Info .Height == rootHeight {
231227 // exit with the order books from memory
232- return info .Orders , nil
228+ return sub . Info .Orders , nil
233229 }
234230 // warn of the remote RPC call to the root chain API
235- latest := uint64 (0 )
236- if info != nil {
237- latest = info .Height
238- }
239- r .log .Warnf ("Executing remote GetOrders call with requested height=%d for rootChainId=%d with latest root height at %d" , rootHeight , rootChainId , latest )
231+ r .log .Warnf ("Executing remote GetOrders call with requested height=%d for rootChainId=%d with latest root height at %d" , rootHeight , rootChainId , sub .Info .Height )
240232 // execute the remote call
241233 books , err := sub .Orders (rootHeight , id )
242234 // if an error occurred during the remote call
@@ -256,7 +248,8 @@ func (r *RCManager) GetOrders(rootChainId, rootHeight, id uint64) (*lib.OrderBoo
256248// Order() returns a specific order from the root order book
257249func (r * RCManager ) GetOrder (rootChainId , height uint64 , orderId string , chainId uint64 ) (* lib.SellOrder , lib.ErrorI ) {
258250 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
259- sub , _ , found := r .subSnapshot (rootChainId )
251+ // if the root chain id is the same as the info
252+ sub , found := r .subscriptions [rootChainId ]
260253 if ! found {
261254 // exit with 'not subscribed' error
262255 return nil , lib .ErrNotSubscribed ()
@@ -267,7 +260,8 @@ func (r *RCManager) GetOrder(rootChainId, height uint64, orderId string, chainId
267260// IsValidDoubleSigner() returns if an address is a valid double signer for a specific 'double sign height'
268261func (r * RCManager ) IsValidDoubleSigner (rootChainId , height uint64 , address string ) (* bool , lib.ErrorI ) {
269262 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
270- sub , _ , found := r .subSnapshot (rootChainId )
263+ // if the root chain id is the same as the info
264+ sub , found := r .subscriptions [rootChainId ]
271265 if ! found {
272266 // exit with 'not subscribed' error
273267 return nil , lib .ErrNotSubscribed ()
@@ -279,7 +273,8 @@ func (r *RCManager) IsValidDoubleSigner(rootChainId, height uint64, address stri
279273// GetMinimumEvidenceHeight() returns the minimum height double sign evidence must have to be 'valid'
280274func (r * RCManager ) GetMinimumEvidenceHeight (rootChainId , height uint64 ) (* uint64 , lib.ErrorI ) {
281275 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
282- sub , _ , found := r .subSnapshot (rootChainId )
276+ // if the root chain id is the same as the info
277+ sub , found := r .subscriptions [rootChainId ]
283278 if ! found {
284279 // exit with 'not subscribed' error
285280 return nil , lib .ErrNotSubscribed ()
@@ -292,7 +287,8 @@ func (r *RCManager) GetMinimumEvidenceHeight(rootChainId, height uint64) (*uint6
292287// TODO should be able to get these from the file or the root-chain upon independence
293288func (r * RCManager ) GetCheckpoint (rootChainId , height , chainId uint64 ) (blockHash lib.HexBytes , err lib.ErrorI ) {
294289 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
295- sub , _ , found := r .subSnapshot (rootChainId )
290+ // if the root chain id is the same as the info
291+ sub , found := r .subscriptions [rootChainId ]
296292 if ! found {
297293 // exit with 'not subscribed' error
298294 return nil , lib .ErrNotSubscribed ()
@@ -304,15 +300,16 @@ func (r *RCManager) GetCheckpoint(rootChainId, height, chainId uint64) (blockHas
304300// GetLotteryWinner() returns the winner of the delegate lottery from the root-chain
305301func (r * RCManager ) GetLotteryWinner (rootChainId , height , id uint64 ) (* lib.LotteryWinner , lib.ErrorI ) {
306302 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
307- sub , info , found := r .subSnapshot (rootChainId )
303+ // if the root chain id is the same as the info
304+ sub , found := r .subscriptions [rootChainId ]
308305 if ! found {
309306 // exit with 'not subscribed' error
310307 return nil , lib .ErrNotSubscribed ()
311308 }
312309 // if the root chain id and height is the same as the info
313- if info != nil && info .Height == height {
310+ if sub . Info .Height == height {
314311 // exit with the lottery winner
315- return info .LotteryWinner , nil
312+ return sub . Info .LotteryWinner , nil
316313 }
317314 // exit with the results of the remote RPC call to the API of the 'root chain'
318315 return sub .Lottery (height , id )
@@ -321,7 +318,8 @@ func (r *RCManager) GetLotteryWinner(rootChainId, height, id uint64) (*lib.Lotte
321318// Transaction() executes a transaction on the root chain
322319func (r * RCManager ) Transaction (rootChainId uint64 , tx lib.TransactionI ) (hash * string , err lib.ErrorI ) {
323320 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
324- sub , _ , found := r .subSnapshot (rootChainId )
321+ // if the root chain id is the same as the info
322+ sub , found := r .subscriptions [rootChainId ]
325323 if ! found {
326324 // exit with 'not subscribed' error
327325 return nil , lib .ErrNotSubscribed ()
@@ -332,7 +330,8 @@ func (r *RCManager) Transaction(rootChainId uint64, tx lib.TransactionI) (hash *
332330// GetDexBatch() queries a 'dex batch on the root chain
333331func (r * RCManager ) GetDexBatch (rootChainId , height , committee uint64 , withPoints bool ) (* lib.DexBatch , lib.ErrorI ) {
334332 defer lib .TimeTrack (r .log , time .Now (), 500 * time .Millisecond )
335- sub , _ , found := r .subSnapshot (rootChainId )
333+ // if the root chain id is the same as the info
334+ sub , found := r .subscriptions [rootChainId ]
336335 if ! found {
337336 // exit with 'not subscribed' error
338337 return nil , lib .ErrNotSubscribed ()
0 commit comments