Skip to content

Commit b10719d

Browse files
authored
Merge pull request #2224 from hirosystems/develop
release to master
2 parents 8f087f1 + 9ce9a33 commit b10719d

File tree

8 files changed

+100
-12
lines changed

8 files changed

+100
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* eslint-disable camelcase */
2+
3+
exports.shorthands = undefined;
4+
5+
exports.up = pgm => {
6+
pgm.createIndex('event_observer_requests', [
7+
'event_path',
8+
{ name: 'receive_timestamp', sort: 'DESC' },
9+
]);
10+
};

src/api/routes/address.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,19 @@ export const AddressRoutes: FastifyPluginAsync<
121121
blockHeight
122122
);
123123
let mempoolBalance: bigint | undefined = undefined;
124+
let mempoolInbound: bigint | undefined = undefined;
125+
let mempoolOutbound: bigint | undefined = undefined;
124126
if (req.query.until_block === undefined) {
125-
const delta = await fastify.db.getPrincipalMempoolStxBalanceDelta(sql, stxAddress);
126-
mempoolBalance = stxBalanceResult.balance + delta;
127+
const pending = await fastify.db.getPrincipalMempoolStxBalanceDelta(sql, stxAddress);
128+
mempoolInbound = pending.inbound;
129+
mempoolOutbound = pending.outbound;
130+
mempoolBalance = stxBalanceResult.balance + pending.delta;
127131
}
128132
const result: AddressStxBalance = {
129133
balance: stxBalanceResult.balance.toString(),
130134
estimated_balance: mempoolBalance?.toString(),
135+
pending_balance_inbound: mempoolInbound?.toString(),
136+
pending_balance_outbound: mempoolOutbound?.toString(),
131137
total_sent: stxBalanceResult.totalSent.toString(),
132138
total_received: stxBalanceResult.totalReceived.toString(),
133139
total_fees_sent: stxBalanceResult.totalFeesSent.toString(),
@@ -211,15 +217,21 @@ export const AddressRoutes: FastifyPluginAsync<
211217
});
212218

213219
let mempoolBalance: bigint | undefined = undefined;
220+
let mempoolInbound: bigint | undefined = undefined;
221+
let mempoolOutbound: bigint | undefined = undefined;
214222
if (req.query.until_block === undefined) {
215-
const delta = await fastify.db.getPrincipalMempoolStxBalanceDelta(sql, stxAddress);
216-
mempoolBalance = stxBalanceResult.balance + delta;
223+
const pending = await fastify.db.getPrincipalMempoolStxBalanceDelta(sql, stxAddress);
224+
mempoolInbound = pending.inbound;
225+
mempoolOutbound = pending.outbound;
226+
mempoolBalance = stxBalanceResult.balance + pending.delta;
217227
}
218228

219229
const result: AddressBalance = {
220230
stx: {
221231
balance: stxBalanceResult.balance.toString(),
222232
estimated_balance: mempoolBalance?.toString(),
233+
pending_balance_inbound: mempoolInbound?.toString(),
234+
pending_balance_outbound: mempoolOutbound?.toString(),
223235
total_sent: stxBalanceResult.totalSent.toString(),
224236
total_received: stxBalanceResult.totalReceived.toString(),
225237
total_fees_sent: stxBalanceResult.totalFeesSent.toString(),

src/api/schemas/entities/balances.ts

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ export const StxBalanceSchema = Type.Object(
2626
description: 'Total STX balance considering pending mempool transactions',
2727
})
2828
),
29+
pending_balance_inbound: Type.Optional(
30+
Type.String({
31+
description: 'Inbound STX balance from pending mempool transactions',
32+
})
33+
),
34+
pending_balance_outbound: Type.Optional(
35+
Type.String({
36+
description: 'Outbound STX balance from pending mempool transactions',
37+
})
38+
),
2939
total_sent: Type.String(),
3040
total_received: Type.String(),
3141
total_fees_sent: Type.String(),

src/datastore/pg-store.ts

+23-8
Original file line numberDiff line numberDiff line change
@@ -2480,8 +2480,8 @@ export class PgStore extends BasePgStore {
24802480
* Returns the total STX balance delta affecting a principal from transactions currently in the
24812481
* mempool.
24822482
*/
2483-
async getPrincipalMempoolStxBalanceDelta(sql: PgSqlClient, principal: string): Promise<bigint> {
2484-
const results = await sql<{ delta: string }[]>`
2483+
async getPrincipalMempoolStxBalanceDelta(sql: PgSqlClient, principal: string) {
2484+
const results = await sql<{ inbound: string; outbound: string; delta: string }[]>`
24852485
WITH sent AS (
24862486
SELECT SUM(COALESCE(token_transfer_amount, 0) + fee_rate) AS total
24872487
FROM mempool_txs
@@ -2496,14 +2496,19 @@ export class PgStore extends BasePgStore {
24962496
SELECT SUM(COALESCE(token_transfer_amount, 0)) AS total
24972497
FROM mempool_txs
24982498
WHERE pruned = false AND token_transfer_recipient_address = ${principal}
2499+
),
2500+
values AS (
2501+
SELECT
2502+
COALESCE((SELECT total FROM received), 0) AS inbound,
2503+
COALESCE((SELECT total FROM sent), 0) + COALESCE((SELECT total FROM sponsored), 0) AS outbound
24992504
)
2500-
SELECT
2501-
COALESCE((SELECT total FROM received), 0)
2502-
- COALESCE((SELECT total FROM sent), 0)
2503-
- COALESCE((SELECT total FROM sponsored), 0)
2504-
AS delta
2505+
SELECT inbound, outbound, (inbound - outbound) AS delta FROM values
25052506
`;
2506-
return BigInt(results[0]?.delta ?? '0');
2507+
return {
2508+
inbound: BigInt(results[0]?.inbound ?? '0'),
2509+
outbound: BigInt(results[0]?.outbound ?? '0'),
2510+
delta: BigInt(results[0]?.delta ?? '0'),
2511+
};
25072512
}
25082513

25092514
async getUnlockedStxSupply(
@@ -4670,4 +4675,14 @@ export class PgStore extends BasePgStore {
46704675
tx_total_size: parseInt(result[0].tx_total_size),
46714676
};
46724677
}
4678+
4679+
/// Returns timestamps for the last Stacks node events received by the API Event Server, grouped
4680+
/// by event type.
4681+
async getLastStacksNodeEventTimestamps() {
4682+
return await this.sql<{ event_path: string; receive_timestamp: Date }[]>`
4683+
SELECT DISTINCT ON (event_path) event_path, receive_timestamp
4684+
FROM event_observer_requests
4685+
ORDER BY event_path, receive_timestamp DESC
4686+
`;
4687+
}
46734688
}

src/event-stream/event-server.ts

+13
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ function createMessageProcessorQueue(db: PgWriteStore): EventMessageHandler {
639639
let metrics:
640640
| {
641641
eventTimer: prom.Histogram;
642+
lastEventTimestamps: prom.Gauge;
642643
blocksInPreviousBurnBlock: prom.Gauge;
643644
}
644645
| undefined;
@@ -650,6 +651,18 @@ function createMessageProcessorQueue(db: PgWriteStore): EventMessageHandler {
650651
labelNames: ['event'],
651652
buckets: prom.exponentialBuckets(50, 3, 10), // 10 buckets, from 50 ms to 15 minutes
652653
}),
654+
lastEventTimestamps: new prom.Gauge({
655+
name: 'stacks_last_event_timestamps',
656+
help: 'Last Stacks node events received timestamp',
657+
labelNames: ['event'] as const,
658+
async collect() {
659+
const events = await db.getLastStacksNodeEventTimestamps();
660+
this.reset();
661+
for (const event of events) {
662+
this.set({ event: event.event_path }, event.receive_timestamp.getTime());
663+
}
664+
},
665+
}),
653666
blocksInPreviousBurnBlock: new prom.Gauge({
654667
name: 'stacks_blocks_in_previous_burn_block',
655668
help: 'Number of Stacks blocks produced in the previous burn block',

tests/api/address.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,8 @@ describe('address tests', () => {
15511551
stx: {
15521552
balance: '88679',
15531553
estimated_balance: '88679',
1554+
pending_balance_inbound: '0',
1555+
pending_balance_outbound: '0',
15541556
total_sent: '6385',
15551557
total_received: '100000',
15561558
total_fees_sent: '4936',
@@ -1601,6 +1603,8 @@ describe('address tests', () => {
16011603
stx: {
16021604
balance: '91',
16031605
estimated_balance: '91',
1606+
pending_balance_inbound: '0',
1607+
pending_balance_outbound: '0',
16041608
total_sent: '15',
16051609
total_received: '1350',
16061610
total_fees_sent: '1244',
@@ -1637,6 +1641,8 @@ describe('address tests', () => {
16371641
const expectedStxResp1 = {
16381642
balance: '91',
16391643
estimated_balance: '91',
1644+
pending_balance_inbound: '0',
1645+
pending_balance_outbound: '0',
16401646
total_sent: '15',
16411647
total_received: '1350',
16421648
total_fees_sent: '1244',
@@ -1668,6 +1674,8 @@ describe('address tests', () => {
16681674
const expectedStxResp1Sponsored = {
16691675
balance: '3766',
16701676
estimated_balance: '3766',
1677+
pending_balance_inbound: '0',
1678+
pending_balance_outbound: '0',
16711679
total_sent: '0',
16721680
total_received: '5000',
16731681
total_fees_sent: '1234',

tests/api/mempool.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,8 @@ describe('mempool tests', () => {
22082208
const balance0 = await supertest(api.server).get(url);
22092209
expect(balance0.body.balance).toEqual('2000');
22102210
expect(balance0.body.estimated_balance).toEqual('2000');
2211+
expect(balance0.body.pending_balance_inbound).toEqual('0');
2212+
expect(balance0.body.pending_balance_outbound).toEqual('0');
22112213

22122214
// STX transfer in mempool
22132215
await db.updateMempoolTxs({
@@ -2223,6 +2225,8 @@ describe('mempool tests', () => {
22232225
const balance1 = await supertest(api.server).get(url);
22242226
expect(balance1.body.balance).toEqual('2000');
22252227
expect(balance1.body.estimated_balance).toEqual('1850'); // Minus amount and fee
2228+
expect(balance1.body.pending_balance_inbound).toEqual('0');
2229+
expect(balance1.body.pending_balance_outbound).toEqual('150');
22262230

22272231
// Contract call in mempool
22282232
await db.updateMempoolTxs({
@@ -2242,6 +2246,8 @@ describe('mempool tests', () => {
22422246
const balance1b = await supertest(api.server).get(url);
22432247
expect(balance1b.body.balance).toEqual('2000');
22442248
expect(balance1b.body.estimated_balance).toEqual('1800'); // Minus fee
2249+
expect(balance1b.body.pending_balance_inbound).toEqual('0');
2250+
expect(balance1b.body.pending_balance_outbound).toEqual('200');
22452251

22462252
// Sponsored tx in mempool
22472253
await db.updateMempoolTxs({
@@ -2258,6 +2264,8 @@ describe('mempool tests', () => {
22582264
const balance2 = await supertest(api.server).get(url);
22592265
expect(balance2.body.balance).toEqual('2000');
22602266
expect(balance2.body.estimated_balance).toEqual('1750'); // Minus fee
2267+
expect(balance2.body.pending_balance_inbound).toEqual('0');
2268+
expect(balance2.body.pending_balance_outbound).toEqual('250');
22612269

22622270
// STX received in mempool
22632271
await db.updateMempoolTxs({
@@ -2273,6 +2281,8 @@ describe('mempool tests', () => {
22732281
const balance3 = await supertest(api.server).get(url);
22742282
expect(balance3.body.balance).toEqual('2000');
22752283
expect(balance3.body.estimated_balance).toEqual('1850'); // Plus amount
2284+
expect(balance3.body.pending_balance_inbound).toEqual('100');
2285+
expect(balance3.body.pending_balance_outbound).toEqual('250');
22762286

22772287
// Confirm all txs
22782288
await db.update(
@@ -2317,5 +2327,7 @@ describe('mempool tests', () => {
23172327
const balance4 = await supertest(api.server).get(url);
23182328
expect(balance4.body.balance).toEqual('1850');
23192329
expect(balance4.body.estimated_balance).toEqual('1850');
2330+
expect(balance4.body.pending_balance_inbound).toEqual('0');
2331+
expect(balance4.body.pending_balance_outbound).toEqual('0');
23202332
});
23212333
});

tests/api/tx.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,8 @@ describe('tx tests', () => {
10311031
const expectedSponsoredRespBefore = {
10321032
balance: '0',
10331033
estimated_balance: '0',
1034+
pending_balance_inbound: '0',
1035+
pending_balance_outbound: '0',
10341036
total_sent: '0',
10351037
total_received: '0',
10361038
total_fees_sent: '0',
@@ -1139,6 +1141,8 @@ describe('tx tests', () => {
11391141
const expectedResp = {
11401142
balance: '0',
11411143
estimated_balance: '0',
1144+
pending_balance_inbound: '0',
1145+
pending_balance_outbound: '0',
11421146
total_sent: '0',
11431147
total_received: '0',
11441148
total_fees_sent: '0',
@@ -1158,6 +1162,8 @@ describe('tx tests', () => {
11581162
stx: {
11591163
balance: '0',
11601164
estimated_balance: '0',
1165+
pending_balance_inbound: '0',
1166+
pending_balance_outbound: '0',
11611167
total_sent: '0',
11621168
total_received: '0',
11631169
total_fees_sent: '0',
@@ -1181,6 +1187,8 @@ describe('tx tests', () => {
11811187
const expectedSponsoredRespAfter = {
11821188
balance: '-300',
11831189
estimated_balance: '-300',
1190+
pending_balance_inbound: '0',
1191+
pending_balance_outbound: '0',
11841192
total_sent: '0',
11851193
total_received: '0',
11861194
total_fees_sent: '300',

0 commit comments

Comments
 (0)