diff --git a/docker/docker-compose.dev.stacks-blockchain.yml b/docker/docker-compose.dev.stacks-blockchain.yml index c226fafb59..2a353119ea 100644 --- a/docker/docker-compose.dev.stacks-blockchain.yml +++ b/docker/docker-compose.dev.stacks-blockchain.yml @@ -1,7 +1,7 @@ version: '3.7' services: stacks-blockchain: - image: 'hirosystems/stacks-api-e2e:stacks3.0-4d11d85' + image: 'hirosystems/stacks-api-e2e:stacks3.0-0a2c0e2' restart: on-failure environment: STACKS_EVENT_OBSERVER: host.docker.internal:3700 diff --git a/docker/docker-compose.dev.stacks-krypton.yml b/docker/docker-compose.dev.stacks-krypton.yml index acf25aefea..6e3ebb6908 100644 --- a/docker/docker-compose.dev.stacks-krypton.yml +++ b/docker/docker-compose.dev.stacks-krypton.yml @@ -1,7 +1,7 @@ version: '3.7' services: stacks-blockchain: - image: 'hirosystems/stacks-api-e2e:stacks3.0-4d11d85' + image: 'hirosystems/stacks-api-e2e:stacks3.0-0a2c0e2' ports: - '18443:18443' # bitcoin regtest JSON-RPC interface - '18444:18444' # bitcoin regtest p2p diff --git a/docs/api/rosetta/rosetta-network-status-response.schema.json b/docs/api/rosetta/rosetta-network-status-response.schema.json index da898e8af9..a272d40482 100644 --- a/docs/api/rosetta/rosetta-network-status-response.schema.json +++ b/docs/api/rosetta/rosetta-network-status-response.schema.json @@ -6,7 +6,8 @@ "current_block_identifier", "current_block_timestamp", "genesis_block_identifier", - "peers" + "peers", + "current_burn_block_height" ], "properties": { "current_block_identifier": { @@ -31,6 +32,10 @@ "items": { "$ref": "./../../entities/rosetta/rosetta-network-peers.schema.json" } + }, + "current_burn_block_height": { + "type": "integer", + "description": "The latest burn block height" } }, "additionalProperties": false diff --git a/docs/entities/rosetta/rosetta-block.schema.json b/docs/entities/rosetta/rosetta-block.schema.json index 9f9f92bd49..8c99d829ae 100644 --- a/docs/entities/rosetta/rosetta-block.schema.json +++ b/docs/entities/rosetta/rosetta-block.schema.json @@ -2,7 +2,7 @@ "type": "object", "title": "RosettaBlock", "description": "Blocks contain an array of Transactions that occurred at a particular BlockIdentifier. A hard requirement for blocks returned by Rosetta implementations is that they MUST be inalterable: once a client has requested and received a block identified by a specific BlockIndentifier, all future calls for that same BlockIdentifier must return the same block contents.", - "required": ["block_identifier", "parent_block_identifier", "timestamp", "transactions"], + "required": ["block_identifier", "parent_block_identifier", "timestamp", "transactions", "metadata"], "additionalProperties": false, "properties": { "block_identifier": { @@ -25,14 +25,10 @@ "metadata": { "type": "object", "description": "meta data", - "required": ["transactions_root", "difficulty"], + "required": ["burn_block_height"], "properties": { - "transactions_root": { - "type": "string", - "description": "" - }, - "difficulty": { - "type": "string", + "burn_block_height": { + "type": "number", "description": "" } } diff --git a/docs/generated.d.ts b/docs/generated.d.ts index 7674fe99bb..a176e4a1f9 100644 --- a/docs/generated.d.ts +++ b/docs/generated.d.ts @@ -440,6 +440,9 @@ export type AbstractTransaction = BaseTransaction & { * An ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ) indicating when this block was mined. */ block_time_iso: string; + /** + * Height of the anchor burn block. + */ burn_block_height: number; /** * Unix timestamp (in seconds) indicating when this block was mined @@ -2361,9 +2364,8 @@ export interface RosettaBlock { /** * meta data */ - metadata?: { - transactions_root: string; - difficulty: string; + metadata: { + burn_block_height: number; [k: string]: unknown | undefined; }; } @@ -3029,6 +3031,10 @@ export interface RosettaNetworkStatusResponse { * Peers information */ peers: RosettaPeers[]; + /** + * The latest burn block height + */ + current_burn_block_height: number; } /** * The block_identifier uniquely identifies a block in a particular network. diff --git a/src/api/controllers/db-controller.ts b/src/api/controllers/db-controller.ts index 6d4da4a6c8..82198a4170 100644 --- a/src/api/controllers/db-controller.ts +++ b/src/api/controllers/db-controller.ts @@ -518,6 +518,9 @@ export async function getRosettaBlockFromDataStore( parent_block_identifier, timestamp: dbBlock.burn_block_time * 1000, transactions: blockTxs.found ? blockTxs.result : [], + metadata: { + burn_block_height: dbBlock.burn_block_height, + }, }; return { found: true, result: apiBlock }; }); diff --git a/src/api/routes/rosetta/network.ts b/src/api/routes/rosetta/network.ts index 8e5960b414..a314e0ac9b 100644 --- a/src/api/routes/rosetta/network.ts +++ b/src/api/routes/rosetta/network.ts @@ -98,6 +98,7 @@ export function createRosettaNetworkRouter(db: PgStore, chainId: ChainID): expre hash: genesis.block_identifier.hash, }, peers, + current_burn_block_height: block.metadata?.burn_block_height ?? 0, }; const nodeInfo = await stacksCoreRpcClient.getInfo(); const referenceNodeTipHeight = nodeInfo.stacks_tip_height; diff --git a/src/tests-rosetta/api.ts b/src/tests-rosetta/api.ts index 327582f33c..8c537a9c6c 100644 --- a/src/tests-rosetta/api.ts +++ b/src/tests-rosetta/api.ts @@ -11,10 +11,12 @@ import { RosettaAccountBalanceRequest, RosettaAccountBalanceResponse, RosettaAmount, + RosettaBlockResponse, RosettaMempoolRequest, RosettaMempoolResponse, RosettaMempoolTransactionRequest, RosettaMempoolTransactionResponse, + RosettaNetworkStatusResponse, RosettaOperation, RosettaTransaction, } from '@stacks/stacks-blockchain-api-types'; @@ -133,7 +135,8 @@ describe('Rosetta API', () => { parent_block_hash: genesisData.block.block_hash, parent_index_block_hash: genesisData.block.index_block_hash, block_height: 2, - index_block_hash: '0x12345678' + index_block_hash: '0x12345678', + burn_block_height: 13334, } const blockData = new TestBlockBuilder(blockBuilderData).build(); @@ -172,7 +175,7 @@ describe('Rosetta API', () => { expect(query1.status).toBe(200); expect(query1.type).toBe('application/json'); - const expectResponse = { + const expectResponse: RosettaNetworkStatusResponse = { current_block_identifier: { index: block.block_height, hash: block.block_hash, @@ -183,18 +186,14 @@ describe('Rosetta API', () => { hash: genesisBlock.block_hash, }, peers: [], + current_burn_block_height: blockBuilderData.burn_block_height, + sync_status: { + current_index: 2, + synced: true, + target_index: 2, + } }; - - expect(JSON.parse(query1.text)).toHaveProperty('sync_status'); - expect(JSON.parse(query1.text).current_block_identifier).toEqual( - expectResponse.current_block_identifier - ); - expect(JSON.parse(query1.text).current_block_timestamp).toEqual( - expectResponse.current_block_timestamp - ); - expect(JSON.parse(query1.text).genesis_block_identifier).toEqual( - expectResponse.genesis_block_identifier - ); + expect(query1.body).toEqual(expectResponse); }); test('block - by index', async () => { @@ -224,7 +223,7 @@ describe('Rosetta API', () => { }); expect(query1.status).toBe(200); expect(query1.type).toBe('application/json'); - expect(JSON.parse(query1.text)).toEqual({ + const expected: RosettaBlockResponse = { block: { block_identifier: { index: blockHeight, @@ -250,8 +249,12 @@ describe('Rosetta API', () => { ], }, ], + metadata: { + burn_block_height: data.block.burn_block_height, + } }, - }); + }; + expect(JSON.parse(query1.text)).toEqual(expected); }); test('block - by hash', async () => { @@ -281,7 +284,7 @@ describe('Rosetta API', () => { }); expect(query1.status).toBe(200); expect(query1.type).toBe('application/json'); - expect(JSON.parse(query1.text)).toEqual({ + const expected: RosettaBlockResponse = { block: { block_identifier: { index: blockHeight, @@ -307,8 +310,12 @@ describe('Rosetta API', () => { ], }, ], + metadata: { + burn_block_height: data.block.burn_block_height, + } }, - }); + }; + expect(JSON.parse(query1.text)).toEqual(expected); }); test('block - get latest', async () => { @@ -327,6 +334,7 @@ describe('Rosetta API', () => { block_height: 2, burn_block_time: 94869286, burn_block_hash: '0xfe15c0d3ebe314fad720a08b839a004c2e6386f5aecc19ec74807d1920cb6aeb', + burn_block_height: 1222, } await db.update(new TestBlockBuilder(block1).addTx().build()); @@ -341,7 +349,7 @@ describe('Rosetta API', () => { expect(query1.status).toBe(200); expect(query1.type).toBe('application/json'); - expect(JSON.parse(query1.text)).toEqual({ + const expected: RosettaBlockResponse = { block: { block_identifier: { index: block2.block_height, @@ -353,8 +361,12 @@ describe('Rosetta API', () => { }, timestamp: block2.burn_block_time * 1000, transactions: expect.objectContaining({}), + metadata: { + burn_block_height: block2.burn_block_height, + } }, - }); + }; + expect(JSON.parse(query1.text)).toEqual(expected); }); test('block/transaction', async () => { diff --git a/stacks-blockchain/docker/Dockerfile b/stacks-blockchain/docker/Dockerfile index 691ad8905b..d283f14e8d 100644 --- a/stacks-blockchain/docker/Dockerfile +++ b/stacks-blockchain/docker/Dockerfile @@ -1,5 +1,5 @@ # Pointed to stacks-blockchain `2.1.0.0.0` git tag -FROM --platform=linux/amd64 hirosystems/stacks-api-e2e:stacks3.0-4d11d85 as build +FROM --platform=linux/amd64 hirosystems/stacks-api-e2e:stacks3.0-0a2c0e2 as build FROM --platform=linux/amd64 debian:bookworm