diff --git a/CHANGELOG.md b/CHANGELOG.md index f9401f96c..411352187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Renames `v3ResponseBody` to `v4ResponseBody` - Renames `isV3ResponseBody` to `isV4ResponseBody` - Renames `HttpV3ApiNotSupportedErrorCode` to `HttpV4ApiNotSupportedErrorCode` +- feat(agent)!: use `/api/v3` for query and read_state requests - feat(assets)!: replaces `@dfinity/{agent,candid,principal}` deps with `@icp-sdk/core` - feat(assets)!: drops support for cjs for the `@dfinity/assets` package - feat(auth-client)!: `@dfinity/auth-client` has been deprecated. Migrate to [`@icp-sdk/auth`](https://js.icp.build/auth/latest/upgrading/v4) diff --git a/e2e/node/basic/__snapshots__/syncTime.test.ts.snap b/e2e/node/basic/__snapshots__/syncTime.test.ts.snap index f23347570..b085cbf0f 100644 --- a/e2e/node/basic/__snapshots__/syncTime.test.ts.snap +++ b/e2e/node/basic/__snapshots__/syncTime.test.ts.snap @@ -46,29 +46,6 @@ exports[`syncTime > on async creation > should sync time on when enabled > V4 re } `; -exports[`syncTime > on async creation > should sync time on when enabled > V4 read state body two 1`] = ` -{ - "content": { - "ingress_expiry": 1746103140000000000n, - "paths": [ - [ - { - "data": [ - 116, - 105, - 109, - 101, - ], - "type": "Buffer", - }, - ], - ], - "request_type": "read_state", - "sender": Any, - }, -} -`; - exports[`syncTime > on error > should not sync time by default > V4 call body 1`] = ` { "content": { @@ -116,6 +93,29 @@ exports[`syncTime > on error > should not sync time by default > V4 call body 1` } `; +exports[`syncTime > on error > should sync time when the local time does not match the subnet time > V3 read state body one 1`] = ` +{ + "content": { + "ingress_expiry": 1746103140000000000n, + "paths": [ + [ + { + "data": [ + 116, + 105, + 109, + 101, + ], + "type": "Buffer", + }, + ], + ], + "request_type": "read_state", + "sender": Any, + }, +} +`; + exports[`syncTime > on error > should sync time when the local time does not match the subnet time > V2 read state body one 1`] = ` { "content": { diff --git a/e2e/node/basic/canisterStatus.test.ts b/e2e/node/basic/canisterStatus.test.ts index 5ff3b332e..fd3f5d0f7 100644 --- a/e2e/node/basic/canisterStatus.test.ts +++ b/e2e/node/basic/canisterStatus.test.ts @@ -12,7 +12,7 @@ import { getCanisterId } from '../utils/canisterid.ts'; import { MockReplica, mockSyncTimeResponse, - prepareV2ReadStateSubnetResponse, + prepareV3ReadStateSubnetResponse, } from '../utils/mock-replica.ts'; import { randomIdentity, randomKeyPair } from '../utils/identity.ts'; @@ -92,14 +92,14 @@ describe('canister status', () => { identity, }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: replicaDate, }); // first try, fails - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); // syncs time @@ -124,7 +124,7 @@ describe('canister status', () => { expect(err.cause.code).toBeInstanceOf(CertificateTimeErrorCode); expect(err.message).toContain('Certificate is signed more than 5 minutes in the past'); } - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); }); it('should sync time and succeed if the certificate is not fresh', async () => { @@ -137,14 +137,14 @@ describe('canister status', () => { identity, }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: replicaDate, }); // first try, fails - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); // sync time, we return the replica date to make the agent sync time properly @@ -162,7 +162,7 @@ describe('canister status', () => { paths: ['subnet'], }), ).resolves.not.toThrow(); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); }); it('should not sync time and succeed if the certificate is not fresh and disableTimeVerification is true', async () => { @@ -175,13 +175,13 @@ describe('canister status', () => { identity, }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: replicaDate, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); @@ -193,7 +193,7 @@ describe('canister status', () => { disableCertificateTimeVerification: true, }), ).resolves.not.toThrow(); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); }); }); }); diff --git a/e2e/node/basic/queryExpiry.test.ts b/e2e/node/basic/queryExpiry.test.ts index 0255dcf2c..2df3967fb 100644 --- a/e2e/node/basic/queryExpiry.test.ts +++ b/e2e/node/basic/queryExpiry.test.ts @@ -2,8 +2,8 @@ import { beforeEach, describe, it, vi, expect } from 'vitest'; import { MockReplica, mockSyncTimeResponse, - prepareV2QueryResponse, - prepareV2ReadStateSubnetResponse, + prepareV3QueryResponse, + prepareV3ReadStateSubnetResponse, } from '../utils/mock-replica.ts'; import { IDL } from '@icp-sdk/core/candid'; import { Principal } from '@icp-sdk/core/principal'; @@ -52,7 +52,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody, requestId } = await prepareV2QueryResponse({ + const { responseBody, requestId } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -61,26 +61,26 @@ describe('queryExpiry', () => { nodeIdentity, date: now, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); const actorResponse = await actor[greetMethodName](greetReq); expect(actorResponse).toEqual(greetRes); - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); - const req = mockReplica.getV2QueryReq(canisterId.toString(), 0); + const req = mockReplica.getV3QueryReq(canisterId.toString(), 0); expect(requestIdOf(req.content)).toEqual(requestId); }); @@ -100,7 +100,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody } = await prepareV2QueryResponse({ + const { responseBody } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -109,16 +109,16 @@ describe('queryExpiry', () => { nodeIdentity, date: now, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: futureDate, // make sure the certificate is fresh for this call }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); @@ -130,7 +130,7 @@ describe('queryExpiry', () => { expectCertificateOutdatedError(e); } - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); }); it('should retry and fail if the timestamp is outside the max ingress expiry (with retry)', async () => { @@ -146,7 +146,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody } = await prepareV2QueryResponse({ + const { responseBody } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -155,21 +155,21 @@ describe('queryExpiry', () => { nodeIdentity, date: now, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); // advance to go over the max ingress expiry (5 minutes) advanceTimeByMilliseconds(timeDiffMsecs); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: now, }); // fetch subnet keys, fails for certificate freshness checks - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); // sync time, keeping a date in the future to make sure the agent still has outdated time @@ -191,8 +191,8 @@ describe('queryExpiry', () => { expect(err.message).toContain('Certificate is signed more than 5 minutes in the past.'); } - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); }); it('should not retry if the timestamp is outside the max ingress expiry (verifyQuerySignatures=false)', async () => { @@ -206,7 +206,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody } = await prepareV2QueryResponse({ + const { responseBody } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -215,22 +215,22 @@ describe('queryExpiry', () => { nodeIdentity, date: now, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); // advance to go over the max ingress expiry (5 minutes) advanceTimeByMilliseconds(6 * MINUTE_TO_MSECS); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(500).send('Should not be called'); }); const actorResponse = await actor[greetMethodName](greetReq); expect(actorResponse).toEqual(greetRes); - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); }); it.each([ @@ -257,7 +257,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody, requestId } = await prepareV2QueryResponse({ + const { responseBody, requestId } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -267,27 +267,27 @@ describe('queryExpiry', () => { timeDiffMsecs, date: replicaDate, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: replicaDate, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); const actorResponse = await actor[greetMethodName](greetReq); expect(actorResponse).toEqual(greetRes); - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(1); - const req = mockReplica.getV2QueryReq(canisterId.toString(), 0); + const req = mockReplica.getV3QueryReq(canisterId.toString(), 0); expect(requestIdOf(req.content)).toEqual(requestId); }, ); @@ -306,7 +306,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody } = await prepareV2QueryResponse({ + const { responseBody } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -316,7 +316,7 @@ describe('queryExpiry', () => { timeDiffMsecs: 0, // sync time is disabled date: replicaDate, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); @@ -328,7 +328,7 @@ describe('queryExpiry', () => { expectCertificateOutdatedError(e); } - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); }); it('should succeed if clock is drifted by more than 5 minutes in the future without syncing it', async () => { @@ -345,7 +345,7 @@ describe('queryExpiry', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody, requestId } = await prepareV2QueryResponse({ + const { responseBody, requestId } = await prepareV3QueryResponse({ canisterId, methodName: greetMethodName, arg: greetArgs, @@ -355,17 +355,17 @@ describe('queryExpiry', () => { timeDiffMsecs: 0, // sync time is disabled date: replicaDate, }); - mockReplica.setV2QuerySpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3QuerySpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(responseBody); }); - const { responseBody: subnetResponseBody } = await prepareV2ReadStateSubnetResponse({ + const { responseBody: subnetResponseBody } = await prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges: [[canisterId.toUint8Array(), canisterId.toUint8Array()]], keyPair: subnetKeyPair, date: replicaDate, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(subnetResponseBody); }); await mockSyncTimeResponse({ @@ -378,10 +378,10 @@ describe('queryExpiry', () => { const actorResponse = await actor[greetMethodName](greetReq); expect(actorResponse).toEqual(greetRes); - expect(mockReplica.getV2QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); + expect(mockReplica.getV3QuerySpy(canisterId.toString())).toHaveBeenCalledTimes(1); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(4); - const req = mockReplica.getV2QueryReq(canisterId.toString(), 0); + const req = mockReplica.getV3QueryReq(canisterId.toString(), 0); expect(requestIdOf(req.content)).toEqual(requestId); }); }); diff --git a/e2e/node/basic/syncTime.test.ts b/e2e/node/basic/syncTime.test.ts index 6eaaf3153..8997894b3 100644 --- a/e2e/node/basic/syncTime.test.ts +++ b/e2e/node/basic/syncTime.test.ts @@ -19,7 +19,7 @@ import { createActor } from '../canisters/counter.ts'; import { MockReplica, mockSyncTimeResponse, - prepareV2ReadStateTimeResponse, + prepareV3ReadStateTimeResponse, prepareV4Response, } from '../utils/mock-replica.ts'; import { randomIdentity, randomKeyPair } from '../utils/identity.ts'; @@ -154,23 +154,23 @@ describe('syncTime', () => { const reqTwo = mockReplica.getV4CallReq(canisterId.toString(), 1); expect(reqTwo).toEqual(req); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 0), + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 0), { sender: anonIdentity.getPrincipal(), }, - 'V2 read state body one', + 'V3 read state body one', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 1), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 1), { sender: anonIdentity.getPrincipal(), }, 'V4 read state body two', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 2), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 2), { sender: anonIdentity.getPrincipal(), }, @@ -215,23 +215,23 @@ describe('syncTime', () => { } expect(mockReplica.getV4CallSpy(canisterId.toString())).toHaveBeenCalledTimes(2); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); expect(agent.hasSyncedTime()).toBe(true); }); }); describe('on async creation', () => { it('should sync time on when enabled', async () => { - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { res.status(200).send(readStateResponse); }); - mockReplica.setV2ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { res.status(200).send(readStateResponse); }); - mockReplica.setV2ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { res.status(200).send(readStateResponse); }); @@ -241,23 +241,23 @@ describe('syncTime', () => { shouldSyncTime: true, }); - expect(mockReplica.getV2ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(3); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(ICP_LEDGER, 0), + expect(mockReplica.getV3ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(3); + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(ICP_LEDGER, 0), { sender: anonIdentity.getPrincipal(), }, 'V4 read state body one', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(ICP_LEDGER, 1), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(ICP_LEDGER, 1), { sender: anonIdentity.getPrincipal(), }, 'V4 read state body two', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(ICP_LEDGER, 2), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(ICP_LEDGER, 2), { sender: anonIdentity.getPrincipal(), }, @@ -267,10 +267,10 @@ describe('syncTime', () => { }); it('should not sync time by default', async () => { - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { res.status(200).send(readStateResponse); }); @@ -281,15 +281,15 @@ describe('syncTime', () => { identity: anonIdentity, }); - expect(mockReplica.getV2ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(0); + expect(mockReplica.getV3ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(0); expect(agent.hasSyncedTime()).toBe(false); }); it('should not sync time when explicitly disabled', async () => { - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(ICP_LEDGER, (_req, res) => { res.status(200).send(readStateResponse); }); @@ -300,7 +300,7 @@ describe('syncTime', () => { identity: anonIdentity, }); - expect(mockReplica.getV2ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(0); + expect(mockReplica.getV3ReadStateSpy(ICP_LEDGER)).toHaveBeenCalledTimes(0); expect(agent.hasSyncedTime()).toBe(false); }); }); @@ -315,16 +315,16 @@ describe('syncTime', () => { }); const actor = await createActor(canisterId, { agent }); - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(readStateResponse); }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(readStateResponse); }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(readStateResponse); }); @@ -359,23 +359,23 @@ describe('syncTime', () => { 'V4 call body', ); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 0), + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(3); + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 0), { sender: anonIdentity.getPrincipal(), }, 'V4 read state body one', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 1), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 1), { sender: anonIdentity.getPrincipal(), }, 'V4 read state body two', ); - expectV2ReadStateRequest( - mockReplica.getV2ReadStateReq(canisterId.toString(), 2), + expectV3ReadStateRequest( + mockReplica.getV3ReadStateReq(canisterId.toString(), 2), { sender: anonIdentity.getPrincipal(), }, @@ -393,10 +393,10 @@ describe('syncTime', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(readStateResponse); }); @@ -430,7 +430,7 @@ describe('syncTime', () => { 'V4 call body', ); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); expect(agent.hasSyncedTime()).toBe(false); }); @@ -444,10 +444,10 @@ describe('syncTime', () => { const actor = await createActor(canisterId, { agent }); const sender = identity.getPrincipal(); - const { responseBody: readStateResponse } = await prepareV2ReadStateTimeResponse({ + const { responseBody: readStateResponse } = await prepareV3ReadStateTimeResponse({ keyPair, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId.toString(), (_req, res) => { res.status(200).send(readStateResponse); }); @@ -482,7 +482,7 @@ describe('syncTime', () => { 'V4 call body', ); - expect(mockReplica.getV2ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); + expect(mockReplica.getV3ReadStateSpy(canisterId.toString())).toHaveBeenCalledTimes(0); expect(agent.hasSyncedTime()).toBe(false); }); }); @@ -518,13 +518,13 @@ function expectV4CallRequest( ); } -interface ExpectedV2ReadStateRequest { +interface ExpectedV3ReadStateRequest { sender: Principal; } -function expectV2ReadStateRequest( +function expectV3ReadStateRequest( actual: UnSigned, - expected: ExpectedV2ReadStateRequest, + expected: ExpectedV3ReadStateRequest, snapshotName?: string, ) { expect(actual.content.sender).toEqual(expected.sender.toUint8Array()); diff --git a/e2e/node/utils/mock-replica.ts b/e2e/node/utils/mock-replica.ts index 26e4e80e7..ee968b471 100644 --- a/e2e/node/utils/mock-replica.ts +++ b/e2e/node/utils/mock-replica.ts @@ -34,8 +34,8 @@ const NANOSECONDS_TO_MSECS = 1_000_000; export enum MockReplicaSpyType { CallV4 = 'CallV4', - ReadStateV2 = 'ReadStateV2', - QueryV2 = 'QueryV2', + ReadStateV3 = 'ReadStateV3', + QueryV3 = 'QueryV3', } export type MockReplicaRequest = Request<{ canisterId: string }, Uint8Array, Uint8Array>; @@ -46,8 +46,8 @@ export type MockReplicaSpy = Mock; export interface MockReplicaSpies { [MockReplicaSpyType.CallV4]?: MockReplicaSpy; - [MockReplicaSpyType.ReadStateV2]?: MockReplicaSpy; - [MockReplicaSpyType.QueryV2]?: MockReplicaSpy; + [MockReplicaSpyType.ReadStateV3]?: MockReplicaSpy; + [MockReplicaSpyType.QueryV3]?: MockReplicaSpy; } function fallbackSpyImpl(spyType: MockReplicaSpyType, canisterId: string): MockReplicaSpyImpl { @@ -73,12 +73,12 @@ export class MockReplica { this.#createEndpointSpy(MockReplicaSpyType.CallV4), ); app.post( - '/api/v2/canister/:canisterId/read_state', - this.#createEndpointSpy(MockReplicaSpyType.ReadStateV2), + '/api/v3/canister/:canisterId/read_state', + this.#createEndpointSpy(MockReplicaSpyType.ReadStateV3), ); app.post( - '/api/v2/canister/:canisterId/query', - this.#createEndpointSpy(MockReplicaSpyType.QueryV2), + '/api/v3/canister/:canisterId/query', + this.#createEndpointSpy(MockReplicaSpyType.QueryV3), ); } @@ -105,24 +105,24 @@ export class MockReplica { this.#setSpyImplOnce(canisterId, MockReplicaSpyType.CallV4, impl); } - public setV2ReadStateSpyImplOnce(canisterId: string, impl: MockReplicaSpyImpl): void { - this.#setSpyImplOnce(canisterId, MockReplicaSpyType.ReadStateV2, impl); + public setV3ReadStateSpyImplOnce(canisterId: string, impl: MockReplicaSpyImpl): void { + this.#setSpyImplOnce(canisterId, MockReplicaSpyType.ReadStateV3, impl); } - public setV2QuerySpyImplOnce(canisterId: string, impl: MockReplicaSpyImpl): void { - this.#setSpyImplOnce(canisterId, MockReplicaSpyType.QueryV2, impl); + public setV3QuerySpyImplOnce(canisterId: string, impl: MockReplicaSpyImpl): void { + this.#setSpyImplOnce(canisterId, MockReplicaSpyType.QueryV3, impl); } public getV4CallSpy(canisterId: string): MockReplicaSpy { return this.#getSpy(canisterId, MockReplicaSpyType.CallV4); } - public getV2ReadStateSpy(canisterId: string): MockReplicaSpy { - return this.#getSpy(canisterId, MockReplicaSpyType.ReadStateV2); + public getV3ReadStateSpy(canisterId: string): MockReplicaSpy { + return this.#getSpy(canisterId, MockReplicaSpyType.ReadStateV3); } - public getV2QuerySpy(canisterId: string): MockReplicaSpy { - return this.#getSpy(canisterId, MockReplicaSpyType.QueryV2); + public getV3QuerySpy(canisterId: string): MockReplicaSpy { + return this.#getSpy(canisterId, MockReplicaSpyType.QueryV3); } public getV4CallReq(canisterId: string, callNumber: number): Signed { @@ -131,14 +131,14 @@ export class MockReplica { return Cbor.decode>(req.body); } - public getV2ReadStateReq(canisterId: string, callNumber: number): UnSigned { - const [req] = this.#getCallParams(canisterId, callNumber, MockReplicaSpyType.ReadStateV2); + public getV3ReadStateReq(canisterId: string, callNumber: number): UnSigned { + const [req] = this.#getCallParams(canisterId, callNumber, MockReplicaSpyType.ReadStateV3); return Cbor.decode>(req.body); } - public getV2QueryReq(canisterId: string, callNumber: number): UnSigned { - const [req] = this.#getCallParams(canisterId, callNumber, MockReplicaSpyType.QueryV2); + public getV3QueryReq(canisterId: string, callNumber: number): UnSigned { + const [req] = this.#getCallParams(canisterId, callNumber, MockReplicaSpyType.QueryV3); return Cbor.decode>(req.body); } @@ -305,26 +305,26 @@ export async function prepareV4Response({ }; } -export interface V2ReadStateTimeOptions { +export interface V3ReadStateTimeOptions { keyPair?: KeyPair; date?: Date; } -export interface V2ReadStateResponse { +export interface V3ReadStateResponse { responseBody: Uint8Array; } /** * Prepares a version 2 read state time response. - * @param {V2ReadStateTimeOptions} options - The options for preparing the response. + * @param {V3ReadStateTimeOptions} options - The options for preparing the response. * @param {Date} options.date - The date for the response. * @param {KeyPair} options.keyPair - The key pair for signing. - * @returns {Promise} A promise that resolves to the prepared response. + * @returns {Promise} A promise that resolves to the prepared response. */ -export async function prepareV2ReadStateTimeResponse({ +export async function prepareV3ReadStateTimeResponse({ date, keyPair, -}: V2ReadStateTimeOptions): Promise { +}: V3ReadStateTimeOptions): Promise { keyPair = keyPair ?? randomKeyPair(); date = date ?? new Date(); @@ -344,7 +344,7 @@ export async function prepareV2ReadStateTimeResponse({ }; } -interface V2ReadStateSubnetOptions { +interface V3ReadStateSubnetOptions { nodeIdentity: Ed25519KeyIdentity; canisterRanges: Array<[Uint8Array, Uint8Array]>; keyPair?: KeyPair; @@ -353,19 +353,19 @@ interface V2ReadStateSubnetOptions { /** * Prepares a version 2 read state subnet response. - * @param {V2ReadStateSubnetOptions} options - The options for preparing the response. + * @param {V3ReadStateSubnetOptions} options - The options for preparing the response. * @param {Ed25519KeyIdentity} options.nodeIdentity - The identity of the node. * @param {Array<[Uint8Array, Uint8Array]>} options.canisterRanges - The canister ranges for the subnet. * @param {KeyPair} options.keyPair - The key pair for signing. * @param {Date} options.date - The date for the response. - * @returns {Promise} A promise that resolves to the prepared response. + * @returns {Promise} A promise that resolves to the prepared response. */ -export async function prepareV2ReadStateSubnetResponse({ +export async function prepareV3ReadStateSubnetResponse({ nodeIdentity, canisterRanges, keyPair, date, -}: V2ReadStateSubnetOptions): Promise { +}: V3ReadStateSubnetOptions): Promise { keyPair = keyPair ?? randomKeyPair(); date = date ?? new Date(); @@ -392,7 +392,7 @@ export async function prepareV2ReadStateSubnetResponse({ }; } -interface V2QueryResponseOptions { +interface V3QueryResponseOptions { canisterId: Principal | string; methodName: string; arg: Uint8Array; @@ -404,14 +404,14 @@ interface V2QueryResponseOptions { date?: Date; } -interface V2QueryResponse { +interface V3QueryResponse { responseBody: Uint8Array; requestId: RequestId; } /** * Prepares a version 2 query response. - * @param {V2QueryResponseOptions} options - The options for preparing the response. + * @param {V3QueryResponseOptions} options - The options for preparing the response. * @param {string} options.canisterId - The ID of the canister. * @param {string} options.methodName - The name of the method being called. * @param {Uint8Array} options.arg - The arguments for the method call. @@ -421,9 +421,9 @@ interface V2QueryResponse { * @param {number} options.timeDiffMsecs - The time difference in milliseconds. * @param {Uint8Array} options.reply - The reply payload. * @param {Date} options.date - The date for the response. - * @returns {Promise} A promise that resolves to the prepared response. + * @returns {Promise} A promise that resolves to the prepared response. */ -export async function prepareV2QueryResponse({ +export async function prepareV3QueryResponse({ canisterId, methodName, arg, @@ -433,7 +433,7 @@ export async function prepareV2QueryResponse({ timeDiffMsecs, reply, date, -}: V2QueryResponseOptions): Promise { +}: V3QueryResponseOptions): Promise { canisterId = Principal.from(canisterId); sender = Principal.from(sender); ingressExpiryInMinutes = ingressExpiryInMinutes ?? 5; @@ -530,17 +530,17 @@ export async function mockSyncTimeResponse({ canisterId, }: MockSyncTimeResponseOptions) { canisterId = Principal.from(canisterId).toText(); - const { responseBody: timeResponseBody } = await prepareV2ReadStateTimeResponse({ + const { responseBody: timeResponseBody } = await prepareV3ReadStateTimeResponse({ keyPair, date, }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId, (_req, res) => { res.status(200).send(timeResponseBody); }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId, (_req, res) => { res.status(200).send(timeResponseBody); }); - mockReplica.setV2ReadStateSpyImplOnce(canisterId, (_req, res) => { + mockReplica.setV3ReadStateSpyImplOnce(canisterId, (_req, res) => { res.status(200).send(timeResponseBody); }); } diff --git a/packages/core/src/agent/actor.test.ts b/packages/core/src/agent/actor.test.ts index ceb8917f5..7011d8df9 100644 --- a/packages/core/src/agent/actor.test.ts +++ b/packages/core/src/agent/actor.test.ts @@ -171,7 +171,7 @@ describe('makeActor', () => { }); expect(calls[1][0].toString()).toEqual( - `http://127.0.0.1/api/v2/canister/${canisterId.toText()}/read_state`, + `http://127.0.0.1/api/v3/canister/${canisterId.toText()}/read_state`, ); expect(calls[1][1]).toEqual({ method: 'POST', diff --git a/packages/core/src/agent/agent/http/index.ts b/packages/core/src/agent/agent/http/index.ts index d05aed361..6188e54fd 100644 --- a/packages/core/src/agent/agent/http/index.ts +++ b/packages/core/src/agent/agent/http/index.ts @@ -660,7 +660,7 @@ export class HttpAgent implements Agent { const delay = tries === 0 ? 0 : backoff.next(); - const url = new URL(`/api/v2/canister/${ecid.toString()}/query`, this.host); + const url = new URL(`/api/v3/canister/${ecid.toString()}/query`, this.host); this.log.print(`fetching "${url.pathname}" with tries:`, { tries, @@ -1119,7 +1119,7 @@ export class HttpAgent implements Agent { transformedRequest = await this.createReadStateRequest(fields, identity); } - const url = new URL(`/api/v2/canister/${canister.toString()}/read_state`, this.host); + const url = new URL(`/api/v3/canister/${canister.toString()}/read_state`, this.host); this.log.print(`fetching "${url.pathname}" with request:`, transformedRequest);