Skip to content

Commit db3c887

Browse files
committed
fix: use deterministic dbBlock.timestamp for CBHE LUT hard fork
Replace non-deterministic Date.now() with dbBlock.timestamp to gate the lowestUsedTimestamp change, ensuring all verifiers produce identical results for the same attestation request.
1 parent f76aab3 commit db3c887

5 files changed

Lines changed: 111 additions & 39 deletions

File tree

src/verification/confirmed-block-height-exists/confirmed-block-height-exists.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ export function responseConfirmedBlockHeightExists(
2626
numberOfConfirmations: number,
2727
request: ConfirmedBlockHeightExists_Request,
2828
) {
29+
// Hard fork: blocks before this timestamp use dbBlock.timestamp as LUT,
30+
// blocks at or after use lowerQueryWindowBlock.timestamp.
2931
// Delete me after 1777366800 Thursday, 28 April 2026 at 11:00:00 CEST
30-
let lut = lowerQueryWindowBlock.timestamp.toString();
31-
const now = Math.round(Date.now() / 1000);
32-
if (now < 1777366800) {
33-
// Thursday, 28 April 2026 at 11:00:00 CEST
34-
lut = dbBlock.timestamp.toString();
35-
}
32+
const CBHE_LUT_FORK_TIMESTAMP = 1777366800;
33+
const lut =
34+
dbBlock.timestamp < CBHE_LUT_FORK_TIMESTAMP
35+
? dbBlock.timestamp.toString()
36+
: lowerQueryWindowBlock.timestamp.toString();
3637

3738
const response = new ConfirmedBlockHeightExists_Response({
3839
attestationType: request.attestationType,

test/e2e_tests/btc/confirmed_block_height_exists/confirmed_block_height_exists_prepare_response.e2e-spec.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ import { expect } from 'chai';
22
import * as request from 'supertest';
33
import { app, baseHooks, getTestFile } from '../helper';
44

5-
// Hard fork for ConfirmedBlockHeightExists lowestUsedTimestamp.
6-
// Before: LUT = dbBlock.timestamp. After: LUT = lowerQueryWindowBlock.timestamp.
7-
// Keep in sync with src/verification/confirmed-block-height-exists/confirmed-block-height-exists.ts.
8-
const CBHE_LUT_HARDFORK_TIMESTAMP = 1777366800;
9-
const isBeforeLutHardfork = () =>
10-
Math.round(Date.now() / 1000) < CBHE_LUT_HARDFORK_TIMESTAMP;
11-
125
describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)})`, () => {
136
baseHooks();
147
it('should get status', async () => {
@@ -38,7 +31,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
3831
);
3932
expect(response.body.response.votingRound).to.be.equal('0');
4033
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
41-
isBeforeLutHardfork() ? '1732779898' : '1732779896',
34+
'1732779898',
4235
);
4336
expect(response.body.response.requestBody.blockNumber).to.be.equal(
4437
'3490156',
@@ -104,7 +97,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
10497
);
10598
expect(response.body.response.votingRound).to.be.equal('0');
10699
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
107-
isBeforeLutHardfork() ? '1732779898' : '1732779897',
100+
'1732779898',
108101
);
109102
expect(response.body.response.requestBody.blockNumber).to.be.equal(
110103
'3490156',
@@ -280,7 +273,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
280273
);
281274
expect(response.body.response.votingRound).to.be.equal('0');
282275
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
283-
isBeforeLutHardfork() ? '1732779898' : '1732779896',
276+
'1732779898',
284277
);
285278
expect(response.body.response.requestBody.blockNumber).to.be.equal(
286279
'3490156',
@@ -326,7 +319,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
326319
);
327320
expect(response.body.response.votingRound).to.be.equal('0');
328321
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
329-
isBeforeLutHardfork() ? '1732779898' : '1732779896',
322+
'1732779898',
330323
);
331324
expect(response.body.response.requestBody.blockNumber).to.be.equal(
332325
'3490156',
@@ -372,7 +365,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
372365
);
373366
expect(response.body.response.votingRound).to.be.equal('0');
374367
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
375-
isBeforeLutHardfork() ? '1732779898' : '1732779896',
368+
'1732779898',
376369
);
377370
expect(response.body.response.requestBody.blockNumber).to.be.equal(
378371
'3490156',
@@ -418,7 +411,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
418411
);
419412
expect(response.body.response.votingRound).to.be.equal('0');
420413
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
421-
isBeforeLutHardfork() ? '1732779898' : '1732779896',
414+
'1732779898',
422415
);
423416
expect(response.body.response.requestBody.blockNumber).to.be.equal(
424417
'3490156',

test/e2e_tests/doge/confirmed_block_height_exists/confirmed_block_height_exists_prepare_response.e2e-spec.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ import { expect } from 'chai';
22
import * as request from 'supertest';
33
import { app, baseHooks, getTestFile } from '../helper';
44

5-
// Hard fork for ConfirmedBlockHeightExists lowestUsedTimestamp.
6-
// Before: LUT = dbBlock.timestamp. After: LUT = lowerQueryWindowBlock.timestamp.
7-
// Keep in sync with src/verification/confirmed-block-height-exists/confirmed-block-height-exists.ts.
8-
const CBHE_LUT_HARDFORK_TIMESTAMP = 1777366800;
9-
const isBeforeLutHardfork = () =>
10-
Math.round(Date.now() / 1000) < CBHE_LUT_HARDFORK_TIMESTAMP;
11-
125
describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)})`, () => {
136
baseHooks();
147
it('should get status', async () => {
@@ -38,7 +31,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
3831
);
3932
expect(response.body.response.votingRound).to.be.equal('0');
4033
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
41-
isBeforeLutHardfork() ? '1732810040' : '1732810035',
34+
'1732810040',
4235
);
4336
expect(response.body.response.requestBody.blockNumber).to.be.equal(
4437
'6724543',
@@ -104,7 +97,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
10497
);
10598
expect(response.body.response.votingRound).to.be.equal('0');
10699
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
107-
isBeforeLutHardfork() ? '1732810040' : '1732810035',
100+
'1732810040',
108101
);
109102
expect(response.body.response.requestBody.blockNumber).to.be.equal(
110103
'6724543',
@@ -280,7 +273,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
280273
);
281274
expect(response.body.response.votingRound).to.be.equal('0');
282275
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
283-
isBeforeLutHardfork() ? '1732810040' : '1732810035',
276+
'1732810040',
284277
);
285278
expect(response.body.response.requestBody.blockNumber).to.be.equal(
286279
'6724543',
@@ -326,7 +319,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
326319
);
327320
expect(response.body.response.votingRound).to.be.equal('0');
328321
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
329-
isBeforeLutHardfork() ? '1732810040' : '1732810035',
322+
'1732810040',
330323
);
331324
expect(response.body.response.requestBody.blockNumber).to.be.equal(
332325
'6724543',

test/e2e_tests/xrp/confirmed_block_height_exists/confirmed_block_height_exists_prepare_response.e2e-spec.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ import { expect } from 'chai';
22
import * as request from 'supertest';
33
import { app, baseHooks, getTestFile } from '../helper';
44

5-
// Hard fork for ConfirmedBlockHeightExists lowestUsedTimestamp.
6-
// Before: LUT = dbBlock.timestamp. After: LUT = lowerQueryWindowBlock.timestamp.
7-
// Keep in sync with src/verification/confirmed-block-height-exists/confirmed-block-height-exists.ts.
8-
const CBHE_LUT_HARDFORK_TIMESTAMP = 1777366800;
9-
const isBeforeLutHardfork = () =>
10-
Math.round(Date.now() / 1000) < CBHE_LUT_HARDFORK_TIMESTAMP;
11-
125
describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)})`, () => {
136
baseHooks();
147
it('should get status', async () => {
@@ -38,7 +31,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
3831
);
3932
expect(response.body.response.votingRound).to.be.equal('0');
4033
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
41-
isBeforeLutHardfork() ? '1733476521' : '1733476512',
34+
'1733476521',
4235
);
4336
expect(response.body.response.requestBody.blockNumber).to.be.equal(
4437
'2882191',
@@ -104,7 +97,7 @@ describe(`/ConfirmedBlockHeightExists/prepareResponse (${getTestFile(__filename)
10497
);
10598
expect(response.body.response.votingRound).to.be.equal('0');
10699
expect(response.body.response.lowestUsedTimestamp).to.be.equal(
107-
isBeforeLutHardfork() ? '1733476521' : '1733476520',
100+
'1733476521',
108101
);
109102
expect(response.body.response.requestBody.blockNumber).to.be.equal(
110103
'2882191',
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { expect } from 'chai';
2+
import { responseConfirmedBlockHeightExists } from '../../src/verification/confirmed-block-height-exists/confirmed-block-height-exists';
3+
import { BlockResult } from '../../src/indexed-query-manager/indexed-query-manager-types';
4+
import { ConfirmedBlockHeightExists_Request } from '../../src/dtos/attestation-types/ConfirmedBlockHeightExists.dto';
5+
import { AttestationResponseStatus } from '../../src/verification/response-status';
6+
7+
const CBHE_LUT_FORK_TIMESTAMP = 1777366800;
8+
9+
function makeRequest(): ConfirmedBlockHeightExists_Request {
10+
return new ConfirmedBlockHeightExists_Request({
11+
attestationType:
12+
'0x436f6e6669726d6564426c6f636b486569676874457869737473000000000000',
13+
sourceId:
14+
'0x7465737442544300000000000000000000000000000000000000000000000000',
15+
requestBody: { blockNumber: '100', queryWindow: '1' },
16+
});
17+
}
18+
19+
function makeBlock(overrides: Partial<BlockResult>): BlockResult {
20+
return {
21+
blockNumber: 100,
22+
timestamp: 0,
23+
transactions: 1,
24+
confirmed: true,
25+
blockHash: '0x' + 'ab'.repeat(32),
26+
...overrides,
27+
};
28+
}
29+
30+
describe('responseConfirmedBlockHeightExists LUT hard fork', () => {
31+
const numberOfConfirmations = 6;
32+
33+
it('uses dbBlock.timestamp as LUT before the fork', () => {
34+
const dbBlock = makeBlock({ timestamp: CBHE_LUT_FORK_TIMESTAMP - 100 });
35+
const lowerQueryWindowBlock = makeBlock({
36+
blockNumber: 90,
37+
timestamp: CBHE_LUT_FORK_TIMESTAMP - 200,
38+
});
39+
40+
const result = responseConfirmedBlockHeightExists(
41+
dbBlock,
42+
lowerQueryWindowBlock,
43+
numberOfConfirmations,
44+
makeRequest(),
45+
);
46+
47+
expect(result.status).to.equal(AttestationResponseStatus.VALID);
48+
expect(result.response.lowestUsedTimestamp).to.equal(
49+
dbBlock.timestamp.toString(),
50+
);
51+
});
52+
53+
it('uses lowerQueryWindowBlock.timestamp as LUT at the fork boundary', () => {
54+
const dbBlock = makeBlock({ timestamp: CBHE_LUT_FORK_TIMESTAMP });
55+
const lowerQueryWindowBlock = makeBlock({
56+
blockNumber: 90,
57+
timestamp: CBHE_LUT_FORK_TIMESTAMP - 100,
58+
});
59+
60+
const result = responseConfirmedBlockHeightExists(
61+
dbBlock,
62+
lowerQueryWindowBlock,
63+
numberOfConfirmations,
64+
makeRequest(),
65+
);
66+
67+
expect(result.status).to.equal(AttestationResponseStatus.VALID);
68+
expect(result.response.lowestUsedTimestamp).to.equal(
69+
lowerQueryWindowBlock.timestamp.toString(),
70+
);
71+
});
72+
73+
it('uses lowerQueryWindowBlock.timestamp as LUT after the fork', () => {
74+
const dbBlock = makeBlock({ timestamp: CBHE_LUT_FORK_TIMESTAMP + 1000 });
75+
const lowerQueryWindowBlock = makeBlock({
76+
blockNumber: 90,
77+
timestamp: CBHE_LUT_FORK_TIMESTAMP + 500,
78+
});
79+
80+
const result = responseConfirmedBlockHeightExists(
81+
dbBlock,
82+
lowerQueryWindowBlock,
83+
numberOfConfirmations,
84+
makeRequest(),
85+
);
86+
87+
expect(result.status).to.equal(AttestationResponseStatus.VALID);
88+
expect(result.response.lowestUsedTimestamp).to.equal(
89+
lowerQueryWindowBlock.timestamp.toString(),
90+
);
91+
});
92+
});

0 commit comments

Comments
 (0)