Skip to content

Commit bd13962

Browse files
authored
fix(rosetta): use Nakamoto block timestamps for epoch3/Nakamoto block responses (#2132)
1 parent bfbf65c commit bd13962

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

src/api/controllers/db-controller.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,17 @@ export async function getRosettaBlockFromDataStore(
541541
}
542542
}
543543

544+
// In epoch2.x, only the burn_block_time is consensus-level. Starting in epoch3, Stacks blocks include a consensus-level timestamp.
545+
// Use `signer_bitvec` field to determine if the block is from epoch3.
546+
let timestamp = dbBlock.burn_block_time * 1000;
547+
if (dbBlock.signer_bitvec) {
548+
timestamp = dbBlock.block_time * 1000;
549+
}
550+
544551
const apiBlock: RosettaBlock = {
545552
block_identifier: { index: dbBlock.block_height, hash: dbBlock.block_hash },
546553
parent_block_identifier,
547-
timestamp: dbBlock.burn_block_time * 1000,
554+
timestamp: timestamp,
548555
transactions: blockTxs.found ? blockTxs.result : [],
549556
metadata: {
550557
burn_block_height: dbBlock.burn_block_height,

tests/rosetta/api.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,94 @@ describe('Rosetta API', () => {
460460
});
461461
});
462462

463+
test('block - Nakamoto timestamps', async () => {
464+
const parentData = new TestBlockBuilder({
465+
block_height: 0,
466+
}).build();
467+
468+
// Epoch2.x block
469+
const block1 = new TestBlockBuilder({
470+
block_height: 1,
471+
block_hash: '0x1234',
472+
index_block_hash: '0x123456',
473+
parent_block_hash: parentData.block.block_hash,
474+
parent_index_block_hash: parentData.block.index_block_hash,
475+
}).build();
476+
block1.block.burn_block_time = 1222;
477+
block1.block.block_time = 1333;
478+
block1.block.signer_bitvec = null;
479+
480+
// Epoch3 block
481+
const block2 = new TestBlockBuilder({
482+
block_height: 2,
483+
block_hash: '0x2234',
484+
index_block_hash: '0x223456',
485+
parent_block_hash: block1.block.block_hash,
486+
parent_index_block_hash: block1.block.index_block_hash,
487+
}).build();
488+
block2.block.burn_block_time = 2222;
489+
block2.block.block_time = 2333;
490+
block2.block.signer_bitvec = '1111';
491+
492+
await db.update(parentData);
493+
await db.update(block1);
494+
await db.update(block2);
495+
496+
const query1 = await supertest(api.address)
497+
.post(`/rosetta/v1/block`)
498+
.send({
499+
network_identifier: { blockchain: 'stacks', network: 'testnet' },
500+
block_identifier: { index: block1.block.block_height },
501+
});
502+
expect(query1.status).toBe(200);
503+
expect(query1.type).toBe('application/json');
504+
const expected1: RosettaBlockResponse = {
505+
block: {
506+
block_identifier: {
507+
index: block1.block.block_height,
508+
hash: block1.block.block_hash,
509+
},
510+
parent_block_identifier: {
511+
index: 1,
512+
hash: '0x1234',
513+
},
514+
timestamp: block1.block.burn_block_time * 1000, // epoch2.x, should be burn-block-time
515+
transactions: [],
516+
metadata: {
517+
burn_block_height: block1.block.burn_block_height,
518+
},
519+
},
520+
};
521+
expect(query1.body).toEqual(expected1);
522+
523+
const query2 = await supertest(api.address)
524+
.post(`/rosetta/v1/block`)
525+
.send({
526+
network_identifier: { blockchain: 'stacks', network: 'testnet' },
527+
block_identifier: { index: block2.block.block_height },
528+
});
529+
expect(query2.status).toBe(200);
530+
expect(query2.type).toBe('application/json');
531+
const expected2: RosettaBlockResponse = {
532+
block: {
533+
block_identifier: {
534+
index: block2.block.block_height,
535+
hash: block2.block.block_hash,
536+
},
537+
parent_block_identifier: {
538+
index: block2.block.block_height - 1,
539+
hash: block2.block.parent_block_hash,
540+
},
541+
timestamp: block2.block.block_time * 1000, // epoch3, should be Stacks-block-time
542+
transactions: [],
543+
metadata: {
544+
burn_block_height: block2.block.burn_block_height,
545+
},
546+
},
547+
};
548+
expect(query2.body).toEqual(expected2);
549+
});
550+
463551
test('stx-transfer-memo block/transaction', async () => {
464552
const parentData = new TestBlockBuilder().addTx().build();
465553
const block: TestBlockArgs = {

0 commit comments

Comments
 (0)