Skip to content

Commit ede5020

Browse files
committed
pool+stats: fetch node tier from the Pool API
1 parent 40d9e88 commit ede5020

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

app/src/__tests__/store/batchStore.spec.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { values } from 'mobx';
1+
import { runInAction, values } from 'mobx';
2+
import * as AUCT from 'types/generated/auctioneer_pb';
23
import { grpc } from '@improbable-eng/grpc-web';
34
import { waitFor } from '@testing-library/react';
45
import * as config from 'config';
56
import { hex } from 'util/strings';
67
import { injectIntoGrpcUnary } from 'util/tests';
7-
import { poolBatchSnapshot } from 'util/tests/sampleData';
8+
import { poolBatchSnapshot, sampleApiResponses } from 'util/tests/sampleData';
89
import { BatchStore, createStore, Store } from 'store';
910
import { BATCH_QUERY_LIMIT } from 'store/stores/batchStore';
1011

@@ -148,6 +149,32 @@ describe('BatchStore', () => {
148149
);
149150
});
150151

152+
it('should fetch node tier', async () => {
153+
// return sample data from gRPC requests instead of the batches defined in beforeEach()
154+
grpcMock.unary.mockImplementation((desc, opts) => {
155+
const path = `${desc.service.serviceName}.${desc.methodName}`;
156+
opts.onEnd({
157+
status: grpc.Code.OK,
158+
message: { toObject: () => sampleApiResponses[path] },
159+
} as any);
160+
return undefined as any;
161+
});
162+
163+
await rootStore.nodeStore.fetchInfo();
164+
165+
expect(store.nodeTier).toBeUndefined();
166+
await store.fetchNodeTier();
167+
expect(store.nodeTier).toBe(AUCT.NodeTier.TIER_1);
168+
169+
// set the pubkey to a random value
170+
runInAction(() => {
171+
rootStore.nodeStore.pubkey = 'asdf';
172+
});
173+
await store.fetchNodeTier();
174+
// confirm the tier is set to T0 if the pubkey is not found in the response
175+
expect(store.nodeTier).toBe(AUCT.NodeTier.TIER_0);
176+
});
177+
151178
it('should start and stop polling', async () => {
152179
let callCount = 0;
153180
injectIntoGrpcUnary(desc => {

app/src/api/pool.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,16 @@ class PoolApi extends BaseApi<PoolEvents> {
234234
return res.toObject();
235235
}
236236

237+
/**
238+
* call the pool `NodeRatings` RPC and return the response
239+
*/
240+
async nodeRatings(pubkey: string): Promise<POOL.NodeRatingResponse.AsObject> {
241+
const req = new POOL.NodeRatingRequest();
242+
req.addNodePubkeys(b64(pubkey));
243+
const res = await this._grpc.request(Trader.NodeRatings, req, this._meta);
244+
return res.toObject();
245+
}
246+
237247
//
238248
// Utility functions to convert user-facing units to API units
239249
//

app/src/store/stores/batchStore.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1-
import { makeAutoObservable, observable, ObservableMap, runInAction, toJS } from 'mobx';
1+
import {
2+
makeAutoObservable,
3+
observable,
4+
ObservableMap,
5+
runInAction,
6+
toJS,
7+
when,
8+
} from 'mobx';
9+
import { NodeTier } from 'types/generated/auctioneer_pb';
210
import { IS_DEV, IS_TEST } from 'config';
311
import debounce from 'lodash/debounce';
12+
import { hex } from 'util/strings';
413
import { Store } from 'store';
514
import { Batch } from 'store/models';
15+
import { Tier } from 'store/models/order';
616

717
export const BATCH_QUERY_LIMIT = 20;
818
const ZERO_BATCH_ID =
@@ -25,6 +35,9 @@ export default class BatchStore {
2535
/** the timestamp of the next batch in seconds */
2636
nextBatchTimestamp = 0;
2737

38+
/** the tier of the current LND node */
39+
nodeTier?: Tier;
40+
2841
/** indicates when batches are being fetched from the backend */
2942
loading = false;
3043

@@ -148,6 +161,28 @@ export default class BatchStore {
148161
}
149162
}
150163

164+
/**
165+
* fetches the next batch timestamp from the API
166+
*/
167+
async fetchNodeTier() {
168+
this._store.log.info('fetching node tier');
169+
try {
170+
const pubkey = this._store.nodeStore.pubkey;
171+
const { nodeRatingsList } = await this._store.api.pool.nodeRatings(pubkey);
172+
runInAction(() => {
173+
const rating = nodeRatingsList.find(r => hex(r.nodePubkey) === pubkey);
174+
if (rating) {
175+
this.nodeTier = rating.nodeTier;
176+
} else {
177+
this.nodeTier = NodeTier.TIER_0;
178+
}
179+
this._store.log.info('updated batchStore.nodeTier', this.nodeTier);
180+
});
181+
} catch (error) {
182+
this._store.appView.handleError(error, 'Unable to fetch the node tier');
183+
}
184+
}
185+
151186
/**
152187
* sets the nextBatchTimestamp and creates a timer to fetch the latest batch, which
153188
* will trigger 3 seconds after the next batch timestamp to allow some time for the
@@ -191,4 +226,16 @@ export default class BatchStore {
191226
this._store.log.info('polling was already stopped');
192227
}
193228
}
229+
230+
/**
231+
* initialize the batch store
232+
*/
233+
init() {
234+
// when the pubkey is fetched from the API and set in the nodeStore, fetch
235+
// the node's tier
236+
when(
237+
() => !!this._store.nodeStore.pubkey && !this.nodeTier,
238+
() => this.fetchNodeTier(),
239+
);
240+
}
194241
}

0 commit comments

Comments
 (0)