From f9118dd21a2dcbd13f03b8e584144c810b04bbc0 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Fri, 24 Jan 2025 11:08:47 +0900 Subject: [PATCH 1/3] checkpoint --- package.json | 7 ++- src/index.ts | 7 +++ test/index.test.mts | 84 +++++++++++++++++++++++++++++++++++ test/shelley-genesis.json | 92 +++++++++++++++++++++++++++++++++++++++ vitest.config.mts | 13 ++++++ 5 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 test/index.test.mts create mode 100644 test/shelley-genesis.json create mode 100644 vitest.config.mts diff --git a/package.json b/package.json index 72f4f79..a5ea649 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "build": "npm run build:node && npm run build:browser", "build:node": "tsup src/index.ts --env.NODE_ENV=node", "build:browser": "tsup src/index.ts --env.NODE_ENV=browser", - "prepublish": "npm run build" + "prepublish": "npm run build", + "test": "vitest" }, "repository": { "type": "git", @@ -29,7 +30,9 @@ "tsup": "^8.2.4", "tsx": "4.19.0", "typescript": "5.5.4", - "@types/node": "22.10.2" + "@types/node": "22.10.2", + "vitest": "^2.1.8", + "@dcspark/cardano-multiplatform-lib-nodejs": "6.0.1" }, "dependencies": { "@connectrpc/connect": "1.4", diff --git a/src/index.ts b/src/index.ts index 5933603..b25d300 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,10 @@ export { SubmitClient as CardanoSubmitClient, WatchClient as CardanoWatchClient, } from "./cardano.js"; +export type { + GenericTipEvent, + GenericTxEvent, + GenericTxInMempoolEvent, + GenericUtxo, + ClientBuilderOptions, +} from "./common.js"; diff --git a/test/index.test.mts b/test/index.test.mts new file mode 100644 index 0000000..b18d014 --- /dev/null +++ b/test/index.test.mts @@ -0,0 +1,84 @@ +import { vi, describe, test, expect } from "vitest"; +import { QueryClient, SyncClient } from "../src/cardano"; +import { createRouterTransport } from "@connectrpc/connect"; +import { + queryConnect, +} from "@utxorpc/spec"; +import genesis from './shelley-genesis.json'; + +// const mockTransport = createRouterTransport(({ service }) => { +// service(queryConnect.QueryService, { +// readParams: () => ({ sentence: "I feel happy." } as any), +// }); +// }); + +// // vitest mock createPromiseClient in @connectrpc/connect to createRouterTransport +// vi.mock("@connectrpc/connect", () => ({ +// createPromiseClient: vi.fn().mockImplementation(() => mockTransport), +// })); + + +describe("QueryClient", () => { + let queryClient = new QueryClient({ + uri: "http://localhost:50051", + }); + test("readParams", async () => { + const params = await queryClient.readParams(); + expect(params).toEqual({ + coinsPerUtxoByte: 0n, + maxTxSize: 4096n, + minFeeCoefficient: 0n, + minFeeConstant: 0n, + maxBlockBodySize: 0n, + maxBlockHeaderSize: 2000000n, + stakeKeyDeposit: 0n, + poolDeposit: 0n, + poolRetirementEpochBound: 0n, + desiredNumberOfPools: 0n, + minPoolCost: 0n, + maxValueSize: 0n, + collateralPercentage: 0n, + maxCollateralInputs: 0n + }); + }); + test("readUtxosByOutputRef", async () => { + const utxo = await queryClient.readUtxosByOutputRef([ + { + txHash: Buffer.from("8c1cb0c06b48dc4238775f81f3276634fbc243131323be95767055ef3d095515", "hex"), + outputIndex: 0, + }, + ]); + expect(Buffer.from(utxo[0].nativeBytes!).toString("hex")).toEqual("8282d818582583581c73d9939a59f42a1f3ca3b6aba56f82e52de28c70cbe36870cff5a197a10242182a001aaa7d769f1ac7145b00"); + }); + test("searchUtxosByAddress", async () => { + const utxo = await queryClient.searchUtxosByAddress(Buffer.from("82d818582583581c73d9939a59f42a1f3ca3b6aba56f82e52de28c70cbe36870cff5a197a10242182a001aaa7d769f", "hex")); + expect(Buffer.from(utxo[0].nativeBytes!).toString("hex")).toEqual("8282d818582583581c73d9939a59f42a1f3ca3b6aba56f82e52de28c70cbe36870cff5a197a10242182a001aaa7d769f1ac7145b00"); + }); + test("searchUtxosByPaymentPart", async () => { + const utxo = await queryClient.searchUtxosByPaymentPart(Buffer.from("c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8", "hex")); + console.log(utxo); + expect(Buffer.from(utxo[0].nativeBytes!).toString("hex")).toEqual("82583900c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c1b00000002540be400"); + }); +}); + +// test('foo', async () => { + +// let syncClient = new SyncClient({ +// uri: "http://localhost:50051", +// }); +// console.log(); +// // for await (const event of syncClient.followTip([{ +// // slot: 601, +// // hash: "f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123", +// // }])) { +// // console.log(event); +// // } +// // const params = await queryClient.readUtxosByOutputRef([ +// // { +// // txHash: Buffer.from("a6ce90a9a5ef8ef73858effdae375ba50f302d3c6c8b587a15eaa8fa98ddf741", "hex"), +// // outputIndex: 0, +// // }, +// // ]); +// // console.log(params); +// // expect(1).toBe(1) +// }) diff --git a/test/shelley-genesis.json b/test/shelley-genesis.json new file mode 100644 index 0000000..cf215ff --- /dev/null +++ b/test/shelley-genesis.json @@ -0,0 +1,92 @@ +{ + "activeSlotsCoeff" : 1.0, + "epochLength" : 600, + "genDelegs" : { + "337bc5ef0f1abf205624555c13a37258c42b46b1259a6b1a6d82574e" : { + "delegate" : "41fd6bb31f34469320aa47cf6ccc3918e58a06d60ea1f2361efe2458", + "vrf" : "7053e3ecd2b19db13e5338aa75fb518fc08b6c218f56ad65760d3eb074be95d4" + } + }, + "initialFunds" : { + "00c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c" : 10000000000, + "004048ff89ca4f88e66598e620aa0c7128c2145d9a181ae9a4a81ca8e3e849af38840c5562dd382be37c9e76545c8191f9d8f6df1d20cfcee0" : 10000000000, + "00ca6e1b1f320d543a24adeabc0aa4627635c7349b639f86f74bdfdd78d31b28c9619a58b3792a7394ab85deb36889c4d7b0632c8167b855d2" : 10000000000, + "0007d781fe8e33883e371f9550c2f1087321fc32e06e80b65e349ccb027702d6880e86e77a0520efa37ede45002a1de43b68692e175b742e67" : 10000000000, + "00627b2598dd71129167825160c564067d1d245e79cc237094815c5cb2b125e30ec2f4ce4059a069e08c3cd82cdfc9451bfb22487f8a25ceef" : 10000000000, + "00c6cf7bd50f37f7e4cc161fc00f07e9b2226ba5552ccaf30d315fa0135bbc8cbd9ab5379f368fc8d3500c37a9d14074cc6ddad89e3686f0e0" : 10000000000, + "005164ab186715c86378020956d892cf72f67636b78967d67cfe7360479130dc89cf7a9bc89109f939956b66f93293ade4c3920b72fd40beea" : 10000000000, + "003dd38742e9848c6f12c13ddb1f9464fc0ce0bb92102768087975317e5a9f869fcd913562c9b0e0f01f77e5359ea780d37f9355f9702eff8b" : 10000000000, + "0088e7e670b45cab2322b518ef7b6f66d30aec0d923dc463e467091a790f67796b9fa71224f2846cebbcf4950c11e040ee124d30f6e164bcd5" : 10000000000, + "00c70b8421617802d3f23956cab1957e1d306cd4808589b41760e97927ebfd6053ba12b38288b2b6d5d4c4618d6a8ce59d50580e9c6f704af5" : 10000000000, + "00c0933b8238f6f3332e48c34cf1a8e0555943b33cd4abc53aefb7d6124b7ce40dd496bdc02b34602f3a773ff7cccee873991e4c8866f3a70b" : 10000000000, + "0069f7d7289de2f01cd1e0265ac5be943b41775abae0ce6b3eac0edee0ce9cadb7cdec2bded3ef8a7bbe3352869bfc1387754c9ee6b1782d9c" : 10000000000, + "00709a7070005c652c27df73dbbde3319a90b127bea96aded1c5fb87a59c51dbcf90fa890174497f3f66a0dad06eb7f131e06567995e9c50a5" : 10000000000, + "00fc576df3a279885a7a4d0fc500372daa1d96f26c6763542ecd2ad8551753024adea37c134edebb68dc0cfaed5a7009e8305fe1fed8d0ccd1" : 10000000000, + "003346a630e6972bf38cce87219db1d63061e7cd324cad88c18e504f2990cac68e973f51256ca938683fa4ea12173d7d047d940fbb883bd0e8" : 10000000000, + "0028b862d001e6a64a02b3560cbc532eab4557593477c39cc523e0b9fc527100898c11e731194171b908aad463770d6cbf7ec8871c4cb1e518" : 10000000000, + "005e0e57040b06e9d71e0f28f126262838a68db0b52b4fd1b3877dda2203d5d7d4f19c5ee3a1ed51bb670779de19d40aaff2e5e9468cc05c5e" : 10000000000, + "00367f65ab69b1e6715c8d5a14964214c9505ed17032266b3209a2c40dcbae9a2a881e603ff39d36e987bacfb87ee98051f222c5fe3efd350c" : 10000000000, + "00c5c4ca287f3b53948b5468e5e23b1c87fe61ce52c0d9afd65d070795038751a619d463e91eaed0a774ebdb2f8e12a01a378a153bc3627323" : 10000000000, + "00ef198fb7c35e1968308a0b75cfee54a46e13e86dd3354283300831d624165c357b5a0413906a0bfea8ba57587331f0836a186d632ed041b8" : 10000000000, + "60ba957a0fff6816021b2afa7900beea68fd10f2d78fb5b64de0d2379c" : 3000000000000000, + "007290ea8fa9433c1045a4c8473959ad608e6c03a58c7de33bdbd3ce6f295b987135610616f3c74e11c94d77b6ced5ccc93a7d719cfb135062" : 300000000000, + "605276322ac7882434173dcc6441905f6737689bd309b68ad8b3614fd8" : 3000000000000000, + "60a0f1aa7dca95017c11e7e373aebcf0c4568cf47ec12b94f8eb5bba8b" : 3000000000000000 + }, + "maxKESEvolutions" : 60, + "maxLovelaceSupply" : 45000000000000000, + "networkId" : "Testnet", + "networkMagic" : 42, + "protocolParams" : { + "a0" : 0.0, + "decentralisationParam" : 0, + "eMax" : 18, + "extraEntropy" : { + "tag" : "NeutralNonce" + }, + "keyDeposit" : 2000000, + "maxBlockBodySize" : 90112, + "maxBlockHeaderSize" : 1100, + "maxTxSize" : 16384, + "minFeeA" : 44, + "minFeeB" : 155381, + "minPoolCost" : 170000000, + "minUTxOValue" : 1000000, + "nOpt" : 100, + "poolDeposit" : 500000000, + "protocolVersion" : { + "major" : 9, + "minor" : 0 + }, + "rho" : 0.003, + "tau" : 0.2 + }, + "securityParam" : 300, + "slotLength" : 1, + "slotsPerKESPeriod" : 129600, + "staking" : { + "pools" : { + "7301761068762f5900bde9eb7c1c15b09840285130f5b0f53606cc57" : { + "cost" : 340000000, + "margin" : 0, + "metadata" : null, + "owners" : [ ], + "pledge" : 0, + "publicKey" : "7301761068762f5900bde9eb7c1c15b09840285130f5b0f53606cc57", + "relays" : [ ], + "rewardAccount" : { + "credential" : { + "keyHash" : "11a14edf73b08a0a27cb98b2c57eb37c780df18fcfcf6785ed5df84a" + }, + "network" : "Testnet" + }, + "vrf" : "c2b62ffa92ad18ffc117ea3abeb161a68885000a466f9c71db5e4731d6630061" + } + }, + "stake" : { + "295b987135610616f3c74e11c94d77b6ced5ccc93a7d719cfb135062" : "7301761068762f5900bde9eb7c1c15b09840285130f5b0f53606cc57" + } + }, + "systemStart" : "2025-01-23T14:17:13.653573Z", + "updateQuorum" : 1 +} \ No newline at end of file diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 0000000..cc9d4c0 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config' +import path from 'node:path' + +export default defineConfig({ + test: { + include: ['test/**/*.test.mts'], + }, + resolve: { + alias: { + "@sdk/grpcTransport": path.resolve(__dirname, "./src/grpcTransport.node.ts"), + }, + }, +}) From 18a947666bf3d2015edb0595624f41116e4b5353 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 16 Mar 2025 02:33:40 +0900 Subject: [PATCH 2/3] finish tests --- test/index.test.mts | 138 +++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 40 deletions(-) diff --git a/test/index.test.mts b/test/index.test.mts index b18d014..327e2c8 100644 --- a/test/index.test.mts +++ b/test/index.test.mts @@ -1,22 +1,5 @@ -import { vi, describe, test, expect } from "vitest"; +import { describe, test, expect } from "vitest"; import { QueryClient, SyncClient } from "../src/cardano"; -import { createRouterTransport } from "@connectrpc/connect"; -import { - queryConnect, -} from "@utxorpc/spec"; -import genesis from './shelley-genesis.json'; - -// const mockTransport = createRouterTransport(({ service }) => { -// service(queryConnect.QueryService, { -// readParams: () => ({ sentence: "I feel happy." } as any), -// }); -// }); - -// // vitest mock createPromiseClient in @connectrpc/connect to createRouterTransport -// vi.mock("@connectrpc/connect", () => ({ -// createPromiseClient: vi.fn().mockImplementation(() => mockTransport), -// })); - describe("QueryClient", () => { let queryClient = new QueryClient({ @@ -56,29 +39,104 @@ describe("QueryClient", () => { }); test("searchUtxosByPaymentPart", async () => { const utxo = await queryClient.searchUtxosByPaymentPart(Buffer.from("c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8", "hex")); - console.log(utxo); expect(Buffer.from(utxo[0].nativeBytes!).toString("hex")).toEqual("82583900c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c1b00000002540be400"); }); + test("searchUtxosByDelegationPart", async () => { + const utxo = await queryClient.searchUtxosByDelegationPart(Buffer.from("f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c", "hex")); + expect(Buffer.from(utxo[0].nativeBytes!).toString("hex")).toEqual("82583900c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c1b00000002540be400"); + }); + test("searchUtxosByAsset", async () => { + const utxo = await queryClient.searchUtxosByAsset(); + expect(utxo.length).toBe(0); // TODO: genesis has no custom assets, so we'd need to setup the tests for this + }); + test("searchUtxosByAddressWithAsset", async () => { + const utxo = await queryClient.searchUtxosByAddressWithAsset(Buffer.from("82d818582583581c73d9939a59f42a1f3ca3b6aba56f82e52de28c70cbe36870cff5a197a10242182a001aaa7d769f", "hex")); + expect(utxo.length).toBe(0); // TODO: genesis has no custom assets, so we'd need to setup the tests for this + }); + test("searchUtxosByPaymentPartWithAsset", async () => { + const utxo = await queryClient.searchUtxosByPaymentPartWithAsset(Buffer.from("c8c47610a36034aac6fc58848bdae5c278d994ff502c05455e3b3ee8", "hex")); + expect(utxo.length).toBe(0); // TODO: genesis has no custom assets, so we'd need to setup the tests for this + }); + test("searchUtxosByDelegationPartWithAsset", async () => { + const utxo = await queryClient.searchUtxosByDelegationPartWithAsset(Buffer.from("f8ed3a0eea0ef835ffa7bbfcde55f7fe9d2cc5d55ea62cecb42bab3c", "hex")); + expect(utxo.length).toBe(0); // TODO: genesis has no custom assets, so we'd need to setup the tests for this + }); +}); + +describe("SyncClient", () => { + let syncClient = new SyncClient({ + uri: "http://localhost:50051", + }); + test("followTip", async () => { + const generator = syncClient.followTip([{ + slot: 601, + hash: 'f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123', + }]); + const block1 = await (generator[Symbol.asyncIterator]()).next(); + expect(block1).toStrictEqual({ + value: { + action: 'reset', + point: { + slot: '601', + hash: 'f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123' + } + }, + done: false + }); + const block2 = await (generator[Symbol.asyncIterator]()).next(); + expect({ body: block2.value.block.body?.toJson(), header: block2.value.block.header?.toJson() }).toEqual({ + body: { + // TODO: this is missing for some reason + // tx: [], + }, + header: { + hash: "ENFFlzZi/rS1v86fbYRg+3xhAW9r7LzZ1MggN6m86rw=", + slot: "602", + height: "1", + } + }) + }); + test("readTip", async () => { + const tip = await syncClient.readTip(); + expect(Number(tip.slot)).toBeGreaterThan(1) + }); + test("fetchBlock", async () => { + const block = await syncClient.fetchBlock({ + slot: 601, + hash: 'f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123', + }); + expect({ body: block.body?.toJson(), header: block.header?.toJson() }).toEqual({ + body: { + // TODO: this is missing for some reason + // tx: [], + }, + header: { + hash: "DdxBJbBKFI8l/2ybtQaqSs/7xEkCBymZGP3vwHWYFiU=", + slot: "601", + // TODO: this is missing for some reason + // height: "0", + } + }) + }); + test("fetchHistory", async () => { + const block = await syncClient.fetchHistory({ + slot: 601, + hash: 'f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123', + }); + expect({ body: block.body?.toJson(), header: block.header?.toJson() }).toEqual({ + body: { + // TODO: this is missing for some reason + // tx: [], + }, + header: { + hash: "DdxBJbBKFI8l/2ybtQaqSs/7xEkCBymZGP3vwHWYFiU=", + slot: "601", + // TODO: this is missing for some reason + // height: "0", + } + }) + }); }); -// test('foo', async () => { - -// let syncClient = new SyncClient({ -// uri: "http://localhost:50051", -// }); -// console.log(); -// // for await (const event of syncClient.followTip([{ -// // slot: 601, -// // hash: "f2158441116a89f567534577323deddc9b44422a06bebfde24b666292e4e3123", -// // }])) { -// // console.log(event); -// // } -// // const params = await queryClient.readUtxosByOutputRef([ -// // { -// // txHash: Buffer.from("a6ce90a9a5ef8ef73858effdae375ba50f302d3c6c8b587a15eaa8fa98ddf741", "hex"), -// // outputIndex: 0, -// // }, -// // ]); -// // console.log(params); -// // expect(1).toBe(1) -// }) +// TODO: test SubmitClient. It's hard since it's stateful, so we need to mock the backend +// TODO: test WatchClient. It's hard since it's stateful, so we need to mock the backend From ea97913d8d368eb49946963af035126987139731 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 16 Mar 2025 02:38:47 +0900 Subject: [PATCH 3/3] PR feedback --- package.json | 3 +-- src/index.ts | 7 ------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/package.json b/package.json index a5ea649..4f75eed 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,7 @@ "tsx": "4.19.0", "typescript": "5.5.4", "@types/node": "22.10.2", - "vitest": "^2.1.8", - "@dcspark/cardano-multiplatform-lib-nodejs": "6.0.1" + "vitest": "^2.1.8" }, "dependencies": { "@connectrpc/connect": "1.4", diff --git a/src/index.ts b/src/index.ts index b25d300..5933603 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,10 +4,3 @@ export { SubmitClient as CardanoSubmitClient, WatchClient as CardanoWatchClient, } from "./cardano.js"; -export type { - GenericTipEvent, - GenericTxEvent, - GenericTxInMempoolEvent, - GenericUtxo, - ClientBuilderOptions, -} from "./common.js";