Skip to content

Commit df01a1b

Browse files
authored
Merge pull request #2325 from hirosystems/master
merge master into develop
2 parents 852a60e + 7e8905c commit df01a1b

17 files changed

+1032
-133
lines changed

CHANGELOG.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,67 @@
1+
## [8.11.5](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.4...v8.11.5) (2025-07-18)
2+
3+
4+
### Bug Fixes
5+
6+
* discount re-orged microblock transactions from ft_balances table ([#2322](https://github.com/hirosystems/stacks-blockchain-api/issues/2322)) ([911c620](https://github.com/hirosystems/stacks-blockchain-api/commit/911c62026e3cc642fcd39e83e0bdd159291b17a9))
7+
8+
## [8.11.4](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.3...v8.11.4) (2025-07-14)
9+
10+
11+
### Bug Fixes
12+
13+
* validate block cursor pagination parameter format ([#2317](https://github.com/hirosystems/stacks-blockchain-api/issues/2317)) ([20e334d](https://github.com/hirosystems/stacks-blockchain-api/commit/20e334dc9a214ad0ee7ff73c3355447efccc9f1a))
14+
15+
## [8.11.3](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.2...v8.11.3) (2025-07-07)
16+
17+
18+
### Bug Fixes
19+
20+
* use burn_block_time in 2.x blocks and block_time after 3.x ([#2314](https://github.com/hirosystems/stacks-blockchain-api/issues/2314)) ([e1d4c61](https://github.com/hirosystems/stacks-blockchain-api/commit/e1d4c618ee8ca60ba457f4ecf37dc33507514d39))
21+
22+
## [8.11.2](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.1...v8.11.2) (2025-06-20)
23+
24+
25+
### Bug Fixes
26+
27+
* do not duplicate miner rewards in v2 balance endpoint ([#2302](https://github.com/hirosystems/stacks-blockchain-api/issues/2302)) ([4c8d514](https://github.com/hirosystems/stacks-blockchain-api/commit/4c8d5143bc08b1e3ad745d1ad18279ed3566819c))
28+
29+
## [8.11.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.0...v8.11.1) (2025-06-02)
30+
31+
32+
### Bug Fixes
33+
34+
* adjust contract ABI writes to read from contract_interface key instead of contract_abi ([#2276](https://github.com/hirosystems/stacks-blockchain-api/issues/2276)) ([82f3fea](https://github.com/hirosystems/stacks-blockchain-api/commit/82f3feaf294206e977f55e7f97fb0e80137d85d7))
35+
36+
## [8.11.1-beta.1](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.11.0...v8.11.1-beta.1) (2025-05-30)
37+
38+
39+
### Bug Fixes
40+
41+
* adjust contract ABI writes to read from contract_interface key instead of contract_abi ([#2276](https://github.com/hirosystems/stacks-blockchain-api/issues/2276)) ([82f3fea](https://github.com/hirosystems/stacks-blockchain-api/commit/82f3feaf294206e977f55e7f97fb0e80137d85d7))
42+
43+
## [8.11.0](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.10.0...v8.11.0) (2025-05-26)
44+
45+
> [!IMPORTANT]
46+
> This release includes an important fix to STX balances reported by the `/extended/v2/addresses/:address/balances/stx` endpoint. A new migration is included that will automatically fix balances for all accounts on launch, but since it's a large migration it could take between 20 minutes to 2 hours to complete depending on deployment resources. No manual intervention or special action is required.
47+
48+
### Features
49+
50+
* add /extended/v2/block-tenures/:height/blocks endpoint ([#2285](https://github.com/hirosystems/stacks-blockchain-api/issues/2285)) ([f5c2e01](https://github.com/hirosystems/stacks-blockchain-api/commit/f5c2e01dd2cc9a2a0cdd608ae68ab2a847cf4ff4))
51+
* stacks core event and rpc proxy body limits configurable via env ([#2278](https://github.com/hirosystems/stacks-blockchain-api/issues/2278)) ([8a54e9d](https://github.com/hirosystems/stacks-blockchain-api/commit/8a54e9d90869ba9af01a0a9507593fff1845e816))
52+
* store and expose vm_error for failed transactions ([#2286](https://github.com/hirosystems/stacks-blockchain-api/issues/2286)) ([7ac7513](https://github.com/hirosystems/stacks-blockchain-api/commit/7ac7513aee4eaf2757f9d3b831172a4a406fd7f5))
53+
54+
55+
### Bug Fixes
56+
57+
* consider microblock transactions in balance calculations ([#2277](https://github.com/hirosystems/stacks-blockchain-api/issues/2277)) ([3418863](https://github.com/hirosystems/stacks-blockchain-api/commit/34188634fab63ed07ce637c17ccf725fd39d6c2d))
58+
* count stx mint data at block 0 towards account balances ([#2289](https://github.com/hirosystems/stacks-blockchain-api/issues/2289)) ([a0cd9f2](https://github.com/hirosystems/stacks-blockchain-api/commit/a0cd9f2330b925dfee89e95c2cd66d7d66e189a6))
59+
* ignore unanchored param for BNS names endpoint ([#2263](https://github.com/hirosystems/stacks-blockchain-api/issues/2263)) ([3d33725](https://github.com/hirosystems/stacks-blockchain-api/commit/3d337256fc186a359d49b88cf321324bc1bd6326))
60+
* keep a table of latest stacks node event timestamps ([#2266](https://github.com/hirosystems/stacks-blockchain-api/issues/2266)) ([6f111ad](https://github.com/hirosystems/stacks-blockchain-api/commit/6f111ad9e4be390ba6f5411e0480713578aa22a9))
61+
* module imports in block tenure routes ([#2287](https://github.com/hirosystems/stacks-blockchain-api/issues/2287)) ([2cb442e](https://github.com/hirosystems/stacks-blockchain-api/commit/2cb442ed2602fe92706ee901c62ff4fac297e4a2))
62+
* **rosetta:** get current block should only join by stacks chain tip information ([#2265](https://github.com/hirosystems/stacks-blockchain-api/issues/2265)) ([78ebad0](https://github.com/hirosystems/stacks-blockchain-api/commit/78ebad09b710d9045c0b9885a0dffbf344771e6a))
63+
* simplify transaction events query ([#2279](https://github.com/hirosystems/stacks-blockchain-api/issues/2279)) ([517ca68](https://github.com/hirosystems/stacks-blockchain-api/commit/517ca6822f465e36d761a97dc8b2eed7fc1dd16c))
64+
165
## [8.10.0](https://github.com/hirosystems/stacks-blockchain-api/compare/v8.9.0...v8.10.0) (2025-04-18)
266

367

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* eslint-disable camelcase */
2+
3+
exports.shorthands = undefined;
4+
5+
exports.up = pgm => {
6+
// Remove old balances.
7+
pgm.sql(`TRUNCATE TABLE ft_balances`);
8+
9+
// Recalculate STX balances
10+
pgm.sql(`
11+
WITH all_balances AS (
12+
SELECT sender AS address, -SUM(amount) AS balance_change
13+
FROM stx_events
14+
WHERE asset_event_type_id IN (1, 3) -- Transfers and Burns affect the sender's balance
15+
AND canonical = true AND microblock_canonical = true
16+
GROUP BY sender
17+
UNION ALL
18+
SELECT recipient AS address, SUM(amount) AS balance_change
19+
FROM stx_events
20+
WHERE asset_event_type_id IN (1, 2) -- Transfers and Mints affect the recipient's balance
21+
AND canonical = true AND microblock_canonical = true
22+
GROUP BY recipient
23+
),
24+
net_balances AS (
25+
SELECT address, SUM(balance_change) AS balance
26+
FROM all_balances
27+
GROUP BY address
28+
),
29+
fees AS (
30+
SELECT address, SUM(total_fees) AS total_fees
31+
FROM (
32+
SELECT sender_address AS address, SUM(fee_rate) AS total_fees
33+
FROM txs
34+
WHERE canonical = true AND microblock_canonical = true AND sponsored = false
35+
GROUP BY sender_address
36+
UNION ALL
37+
SELECT sponsor_address AS address, SUM(fee_rate) AS total_fees
38+
FROM txs
39+
WHERE canonical = true AND microblock_canonical = true AND sponsored = true
40+
GROUP BY sponsor_address
41+
) AS subquery
42+
GROUP BY address
43+
),
44+
rewards AS (
45+
SELECT
46+
recipient AS address,
47+
SUM(
48+
coinbase_amount + tx_fees_anchored + tx_fees_streamed_confirmed + tx_fees_streamed_produced
49+
) AS total_rewards
50+
FROM miner_rewards
51+
WHERE canonical = true
52+
GROUP BY recipient
53+
),
54+
all_addresses AS (
55+
SELECT address FROM net_balances
56+
UNION
57+
SELECT address FROM fees
58+
UNION
59+
SELECT address FROM rewards
60+
)
61+
INSERT INTO ft_balances (address, balance, token)
62+
SELECT
63+
aa.address,
64+
COALESCE(nb.balance, 0) - COALESCE(f.total_fees, 0) + COALESCE(r.total_rewards, 0) AS balance,
65+
'stx' AS token
66+
FROM all_addresses aa
67+
LEFT JOIN net_balances nb ON aa.address = nb.address
68+
LEFT JOIN fees f ON aa.address = f.address
69+
LEFT JOIN rewards r ON aa.address = r.address
70+
`);
71+
72+
// Recalculate FT balances
73+
pgm.sql(`
74+
WITH all_balances AS (
75+
SELECT sender AS address, asset_identifier, -SUM(amount) AS balance_change
76+
FROM ft_events
77+
WHERE asset_event_type_id IN (1, 3) -- Transfers and Burns affect the sender's balance
78+
AND canonical = true
79+
AND microblock_canonical = true
80+
GROUP BY sender, asset_identifier
81+
UNION ALL
82+
SELECT recipient AS address, asset_identifier, SUM(amount) AS balance_change
83+
FROM ft_events
84+
WHERE asset_event_type_id IN (1, 2) -- Transfers and Mints affect the recipient's balance
85+
AND canonical = true
86+
AND microblock_canonical = true
87+
GROUP BY recipient, asset_identifier
88+
),
89+
net_balances AS (
90+
SELECT address, asset_identifier, SUM(balance_change) AS balance
91+
FROM all_balances
92+
GROUP BY address, asset_identifier
93+
)
94+
INSERT INTO ft_balances (address, balance, token)
95+
SELECT address, balance, asset_identifier AS token
96+
FROM net_balances
97+
`);
98+
};
99+
100+
exports.down = pgm => {};

src/api/routes/v2/addresses.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export const AddressRoutesV2: FastifyPluginAsync<
174174
sql,
175175
stxAddress,
176176
});
177-
let stxBalance = stxBalancesResult.found ? stxBalancesResult.result.balance : 0n;
177+
const stxBalance = stxBalancesResult.found ? stxBalancesResult.result.balance : 0n;
178178

179179
// Get pox-locked info for STX token
180180
const stxPoxLockedResult = await fastify.db.v2.getStxPoxLockedAtBlock({
@@ -190,7 +190,6 @@ export const AddressRoutesV2: FastifyPluginAsync<
190190
stxAddress,
191191
blockHeight: chainTip.block_height,
192192
});
193-
stxBalance += totalMinerRewardsReceived;
194193

195194
const result: StxBalance = {
196195
balance: stxBalance.toString(),

src/api/routes/v2/block-tenures.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { handleBlockCache } from '../../../api/controllers/cache-controller';
55
import { getPagingQueryLimit, ResourceType } from '../../../api/pagination';
66
import { CursorOffsetParam, LimitParam } from '../../../api/schemas/params';
77
import { BlockListV2ResponseSchema } from '../../../api/schemas/responses/responses';
8-
import { BlockTenureParamsSchema } from './schemas';
8+
import { BlockTenureParamsSchema, BlockCursorParamSchema } from './schemas';
99
import { NotFoundError } from '../../../errors';
1010
import { NakamotoBlock } from '../../../api/schemas/entities/block';
1111
import { parseDbNakamotoBlock } from './helpers';
@@ -28,7 +28,7 @@ export const BlockTenureRoutes: FastifyPluginAsync<
2828
querystring: Type.Object({
2929
limit: LimitParam(ResourceType.Block),
3030
offset: CursorOffsetParam({ resource: ResourceType.Block }),
31-
cursor: Type.Optional(Type.String({ description: 'Cursor for pagination' })),
31+
cursor: Type.Optional(BlockCursorParamSchema),
3232
}),
3333
response: {
3434
200: BlockListV2ResponseSchema,

src/api/routes/v2/blocks.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { handleBlockCache, handleChainTipCache } from '../../../api/controllers/cache-controller';
2-
import { BlockParamsSchema, cleanBlockHeightOrHashParam, parseBlockParam } from './schemas';
2+
import {
3+
BlockParamsSchema,
4+
cleanBlockHeightOrHashParam,
5+
BlockCursorParamSchema,
6+
parseBlockParam,
7+
} from './schemas';
38
import { parseDbNakamotoBlock } from './helpers';
49
import { InvalidRequestError, NotFoundError } from '../../../errors';
510
import { parseDbTx } from '../../../api/controllers/db-controller';
611
import { FastifyPluginAsync } from 'fastify';
712
import { Type, TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
813
import { Server } from 'node:http';
914
import { CursorOffsetParam, LimitParam, OffsetParam } from '../../schemas/params';
10-
import { getPagingQueryLimit, pagingQueryLimits, ResourceType } from '../../pagination';
15+
import { getPagingQueryLimit, ResourceType } from '../../pagination';
1116
import { PaginatedResponse } from '../../schemas/util';
12-
import {
13-
NakamotoBlock,
14-
NakamotoBlockSchema,
15-
SignerSignatureSchema,
16-
} from '../../schemas/entities/block';
17+
import { NakamotoBlock, NakamotoBlockSchema } from '../../schemas/entities/block';
1718
import { TransactionSchema } from '../../schemas/entities/transactions';
1819
import {
1920
BlockListV2ResponseSchema,
@@ -37,7 +38,7 @@ export const BlockRoutesV2: FastifyPluginAsync<
3738
querystring: Type.Object({
3839
limit: LimitParam(ResourceType.Block),
3940
offset: CursorOffsetParam({ resource: ResourceType.Block }),
40-
cursor: Type.Optional(Type.String({ description: 'Cursor for pagination' })),
41+
cursor: Type.Optional(BlockCursorParamSchema),
4142
}),
4243
response: {
4344
200: BlockListV2ResponseSchema,

src/api/routes/v2/schemas.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ export const PoxSignerLimitParamSchema = Type.Integer({
7171
description: 'PoX signers per page',
7272
});
7373

74+
export const BlockCursorParamSchema = Type.String({
75+
pattern: '^0x[a-fA-F0-9]{64}$',
76+
description: 'Cursor for block pagination',
77+
});
78+
7479
export type BlockIdParam =
7580
| { type: 'height'; height: number }
7681
| { type: 'hash'; hash: string }

src/datastore/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,7 @@ export interface DbPoxCycleSignerStacker {
11121112

11131113
interface ReOrgEntities {
11141114
blocks: number;
1115+
microblockHashes: string[];
11151116
microblocks: number;
11161117
minerRewards: number;
11171118
txs: number;

src/datastore/helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,7 @@ export function newReOrgUpdatedEntities(): ReOrgUpdatedEntities {
13161316
return {
13171317
markedCanonical: {
13181318
blocks: 0,
1319+
microblockHashes: [],
13191320
microblocks: 0,
13201321
minerRewards: 0,
13211322
txs: 0,
@@ -1336,6 +1337,7 @@ export function newReOrgUpdatedEntities(): ReOrgUpdatedEntities {
13361337
},
13371338
markedNonCanonical: {
13381339
blocks: 0,
1340+
microblockHashes: [],
13391341
microblocks: 0,
13401342
minerRewards: 0,
13411343
txs: 0,

0 commit comments

Comments
 (0)