pacifica-signer.contract.test.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /**
  2. * Pacifica签名器契约测试
  3. *
  4. * 验证IPacificaSigner接口的契约实现
  5. * 测试Ed25519签名、批量操作、消息序列化等Pacifica特定功能
  6. */
  7. import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
  8. import {
  9. PacificaSigner,
  10. PacificaSignRequest,
  11. PacificaSignResponse,
  12. PacificaVerifyRequest,
  13. PacificaOrderType,
  14. PacificaOrderMessage,
  15. PacificaCancelMessage,
  16. PACIFICA_CONSTANTS,
  17. Platform,
  18. SignResult
  19. } from '../../src/index';
  20. describe('IPacificaSigner Contract Tests', () => {
  21. let signer: PacificaSigner;
  22. const testAccountId = 'pacifica-signer-test-001';
  23. beforeEach(async () => {
  24. // 创建PacificaSigner实例并添加测试账户
  25. const { PacificaSigner } = await import('../../src/platforms/pacifica/PacificaSigner');
  26. signer = new PacificaSigner();
  27. // 添加测试账户私钥(64字符十六进制)
  28. const testPrivateKey = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
  29. signer.addAccount(testAccountId, testPrivateKey);
  30. });
  31. afterEach(async () => {
  32. // 清理资源
  33. });
  34. describe('平台接口验证', () => {
  35. test('应该正确标识Pacifica平台', () => {
  36. expect(signer.platform).toBe(Platform.PACIFICA);
  37. });
  38. });
  39. describe('Ed25519签名功能', () => {
  40. test('应该能对Pacifica订单进行签名', async () => {
  41. const orderMessage: PacificaOrderMessage = {
  42. order_type: PacificaOrderType.LIMIT,
  43. symbol: 'BTC-USD',
  44. side: 'buy',
  45. size: '0.001',
  46. price: '65000.00',
  47. client_id: 'test-order-001',
  48. timestamp: Date.now(),
  49. expiry: Date.now() + 300000
  50. };
  51. const messageBytes = new TextEncoder().encode(JSON.stringify(orderMessage));
  52. const request: PacificaSignRequest = {
  53. accountId: testAccountId,
  54. message: messageBytes,
  55. orderType: PacificaOrderType.LIMIT,
  56. options: {
  57. timeout: 30000,
  58. includeTimestamp: true,
  59. encoding: 'base64'
  60. }
  61. };
  62. const response = await signer.signOrder(request);
  63. expect(response.success).toBe(true);
  64. expect(response.signature).toBeDefined();
  65. expect(response.signature.length).toBe(PACIFICA_CONSTANTS.SIGNATURE_BASE64_LENGTH);
  66. expect(response.algorithm).toBe('ed25519');
  67. expect(response.publicKey).toBeDefined();
  68. expect(response.publicKey.length).toBe(PACIFICA_CONSTANTS.PUBLIC_KEY_BASE58_LENGTH);
  69. expect(response.orderType).toBe(PacificaOrderType.LIMIT);
  70. expect(response.timestamp).toBeInstanceOf(Date);
  71. expect(response.executionTime).toBeLessThan(50); // NFR-002: <50ms
  72. });
  73. test('应该能对市价单进行签名', async () => {
  74. const orderMessage: PacificaOrderMessage = {
  75. order_type: PacificaOrderType.MARKET,
  76. symbol: 'ETH-USD',
  77. side: 'sell',
  78. size: '0.1',
  79. client_id: 'market-order-001',
  80. timestamp: Date.now()
  81. };
  82. const messageBytes = new TextEncoder().encode(JSON.stringify(orderMessage));
  83. const request: PacificaSignRequest = {
  84. accountId: testAccountId,
  85. message: messageBytes,
  86. orderType: PacificaOrderType.MARKET
  87. };
  88. const response = await signer.signOrder(request);
  89. expect(response.success).toBe(true);
  90. expect(response.algorithm).toBe('ed25519');
  91. expect(response.orderType).toBe(PacificaOrderType.MARKET);
  92. });
  93. test('应该能对取消订单进行签名', async () => {
  94. const cancelMessage: PacificaCancelMessage = {
  95. action: 'cancel',
  96. order_type: 'cancel',
  97. order_id: 'order-to-cancel-123',
  98. timestamp: Date.now()
  99. };
  100. const messageBytes = new TextEncoder().encode(JSON.stringify(cancelMessage));
  101. const request: PacificaSignRequest = {
  102. accountId: testAccountId,
  103. message: messageBytes,
  104. orderType: PacificaOrderType.CANCEL
  105. };
  106. const response = await signer.signOrder(request);
  107. expect(response.success).toBe(true);
  108. expect(response.orderType).toBe(PacificaOrderType.CANCEL);
  109. });
  110. });
  111. describe('签名验证功能', () => {
  112. test('应该能验证有效的Ed25519签名', async () => {
  113. // 首先创建一个签名
  114. const orderMessage: PacificaOrderMessage = {
  115. order_type: PacificaOrderType.LIMIT,
  116. symbol: 'BTC-USD',
  117. side: 'buy',
  118. size: '0.001',
  119. price: '65000.00',
  120. client_id: 'verify-test-001',
  121. timestamp: Date.now()
  122. };
  123. const messageBytes = new TextEncoder().encode(JSON.stringify(orderMessage));
  124. const signResponse = await signer.signOrder({
  125. accountId: testAccountId,
  126. message: messageBytes,
  127. orderType: PacificaOrderType.LIMIT
  128. });
  129. expect(signResponse.success).toBe(true);
  130. // 然后验证签名
  131. const verifyRequest: PacificaVerifyRequest = {
  132. accountId: testAccountId,
  133. message: messageBytes,
  134. signature: signResponse.signature,
  135. publicKey: signResponse.publicKey,
  136. orderType: PacificaOrderType.LIMIT
  137. };
  138. const verifyResponse = await signer.verifySignature(verifyRequest);
  139. expect(verifyResponse.success).toBe(true);
  140. expect(verifyResponse.isValid).toBe(true);
  141. expect(verifyResponse.algorithm).toBe('ed25519');
  142. expect(verifyResponse.publicKey).toBe(signResponse.publicKey);
  143. expect(verifyResponse.timestamp).toBeInstanceOf(Date);
  144. expect(verifyResponse.verificationId).toBeDefined();
  145. });
  146. test('应该拒绝被篡改的消息签名', async () => {
  147. // 创建原始签名
  148. const originalMessage = new TextEncoder().encode('original message');
  149. const signResponse = await signer.signOrder({
  150. accountId: testAccountId,
  151. message: originalMessage,
  152. orderType: PacificaOrderType.MARKET
  153. });
  154. // 尝试验证不同的消息(篡改)
  155. const tamperedMessage = new TextEncoder().encode('tampered message');
  156. const verifyRequest: PacificaVerifyRequest = {
  157. accountId: testAccountId,
  158. message: tamperedMessage,
  159. signature: signResponse.signature,
  160. publicKey: signResponse.publicKey
  161. };
  162. const verifyResponse = await signer.verifySignature(verifyRequest);
  163. expect(verifyResponse.success).toBe(true); // 验证操作成功
  164. expect(verifyResponse.isValid).toBe(false); // 但签名无效
  165. });
  166. test('应该拒绝无效格式的签名', async () => {
  167. const message = new TextEncoder().encode('test message');
  168. const verifyRequest: PacificaVerifyRequest = {
  169. accountId: testAccountId,
  170. message: message,
  171. signature: 'invalid-signature-format',
  172. publicKey: 'valid-looking-public-key-base58'
  173. };
  174. const verifyResponse = await signer.verifySignature(verifyRequest);
  175. expect(verifyResponse.success).toBe(false);
  176. expect(verifyResponse.error).toBeDefined();
  177. expect(verifyResponse.error).toContain('INVALID');
  178. });
  179. });
  180. describe('公钥管理', () => {
  181. test('应该能获取账户公钥', async () => {
  182. const publicKey = await signer.getPublicKey(testAccountId);
  183. expect(publicKey).toBeDefined();
  184. expect(typeof publicKey).toBe('string');
  185. expect(publicKey.length).toBe(PACIFICA_CONSTANTS.PUBLIC_KEY_BASE58_LENGTH);
  186. // 验证Base58格式(基本检查)
  187. expect(/^[1-9A-HJ-NP-Za-km-z]+$/.test(publicKey)).toBe(true);
  188. });
  189. test('应该为不存在的账户返回错误', async () => {
  190. await expect(signer.getPublicKey('non-existent-account'))
  191. .rejects.toThrow('ACCOUNT_NOT_FOUND');
  192. });
  193. });
  194. describe('批量签名功能', () => {
  195. test('应该能执行批量签名操作', async () => {
  196. const orders: PacificaOrderMessage[] = [
  197. {
  198. order_type: PacificaOrderType.LIMIT,
  199. symbol: 'BTC-USD',
  200. side: 'buy',
  201. size: '0.001',
  202. price: '65000.00',
  203. client_id: 'batch-order-1',
  204. timestamp: Date.now()
  205. },
  206. {
  207. order_type: PacificaOrderType.MARKET,
  208. symbol: 'ETH-USD',
  209. side: 'sell',
  210. size: '0.1',
  211. client_id: 'batch-order-2',
  212. timestamp: Date.now()
  213. },
  214. {
  215. action: 'cancel',
  216. order_type: PacificaOrderType.CANCEL,
  217. order_id: 'order-to-cancel',
  218. timestamp: Date.now(),
  219. side: 'buy', // Add required fields for compatibility
  220. size: '0'
  221. } as any
  222. ];
  223. const requests: PacificaSignRequest[] = orders.map((order, index) => ({
  224. accountId: testAccountId,
  225. message: new TextEncoder().encode(JSON.stringify(order)),
  226. orderType: order.order_type as PacificaOrderType
  227. }));
  228. const startTime = Date.now();
  229. const responses = await signer.signBatch(requests);
  230. const totalTime = Date.now() - startTime;
  231. expect(responses).toHaveLength(requests.length);
  232. expect(totalTime).toBeLessThan(300); // 批量操作应该在300ms内完成
  233. responses.forEach((response, index) => {
  234. expect(response.success).toBe(true);
  235. expect(response.signature).toBeDefined();
  236. expect(response.algorithm).toBe('ed25519');
  237. expect(response.orderType).toBe(orders[index]?.order_type);
  238. expect(response.executionTime).toBeLessThan(50);
  239. });
  240. // 验证所有签名都是唯一的
  241. const signatures = responses.map(r => r.signature);
  242. const uniqueSignatures = new Set(signatures);
  243. expect(uniqueSignatures.size).toBe(signatures.length);
  244. });
  245. test('应该拒绝超过最大批量大小的请求', async () => {
  246. const requests: PacificaSignRequest[] = Array.from(
  247. { length: PACIFICA_CONSTANTS.MAX_BATCH_SIZE + 1 },
  248. (_, index) => ({
  249. accountId: testAccountId,
  250. message: new TextEncoder().encode(`batch message ${index}`),
  251. orderType: PacificaOrderType.MARKET
  252. })
  253. );
  254. await expect(signer.signBatch(requests))
  255. .rejects.toThrow('BATCH_SIZE_EXCEEDED');
  256. });
  257. test('应该处理批量请求中的部分失败', async () => {
  258. const requests: PacificaSignRequest[] = [
  259. {
  260. accountId: testAccountId,
  261. message: new TextEncoder().encode('valid message 1'),
  262. orderType: PacificaOrderType.LIMIT
  263. },
  264. {
  265. accountId: 'invalid-account',
  266. message: new TextEncoder().encode('valid message 2'),
  267. orderType: PacificaOrderType.MARKET
  268. },
  269. {
  270. accountId: testAccountId,
  271. message: new TextEncoder().encode('valid message 3'),
  272. orderType: PacificaOrderType.CANCEL
  273. }
  274. ];
  275. const responses = await signer.signBatch(requests);
  276. expect(responses).toHaveLength(3);
  277. expect(responses[0]?.success).toBe(true);
  278. expect(responses[1]?.success).toBe(false);
  279. expect(responses[1]?.error).toContain('ACCOUNT_NOT_FOUND');
  280. expect(responses[2]?.success).toBe(true);
  281. });
  282. });
  283. describe('签名选项和编码', () => {
  284. test('应该支持不同的签名编码格式', async () => {
  285. const message = new TextEncoder().encode('encoding test message');
  286. const encodings: Array<'base64' | 'base58' | 'hex'> = ['base64', 'base58', 'hex'];
  287. for (const encoding of encodings) {
  288. const request: PacificaSignRequest = {
  289. accountId: testAccountId,
  290. message: message,
  291. orderType: PacificaOrderType.MARKET,
  292. options: { encoding }
  293. };
  294. const response = await signer.signOrder(request);
  295. expect(response.success).toBe(true);
  296. expect(response.signature).toBeDefined();
  297. // 验证编码格式
  298. switch (encoding) {
  299. case 'base64':
  300. expect(/^[A-Za-z0-9+/]+=*$/.test(response.signature)).toBe(true);
  301. break;
  302. case 'base58':
  303. expect(/^[1-9A-HJ-NP-Za-km-z]+$/.test(response.signature)).toBe(true);
  304. break;
  305. case 'hex':
  306. expect(/^[0-9a-fA-F]+$/.test(response.signature)).toBe(true);
  307. break;
  308. }
  309. }
  310. });
  311. test('应该支持时间戳包含选项', async () => {
  312. const message = new TextEncoder().encode('timestamp test message');
  313. // 包含时间戳
  314. const withTimestamp = await signer.signOrder({
  315. accountId: testAccountId,
  316. message: message,
  317. orderType: PacificaOrderType.LIMIT,
  318. options: { includeTimestamp: true }
  319. });
  320. // 不包含时间戳
  321. const withoutTimestamp = await signer.signOrder({
  322. accountId: testAccountId,
  323. message: message,
  324. orderType: PacificaOrderType.LIMIT,
  325. options: { includeTimestamp: false }
  326. });
  327. expect(withTimestamp.success).toBe(true);
  328. expect(withoutTimestamp.success).toBe(true);
  329. // 签名应该不同(因为时间戳的存在)
  330. expect(withTimestamp.signature).not.toBe(withoutTimestamp.signature);
  331. });
  332. test('应该遵守签名超时设置', async () => {
  333. const message = new TextEncoder().encode('timeout test message');
  334. // 极短超时应该失败
  335. const shortTimeoutRequest: PacificaSignRequest = {
  336. accountId: testAccountId,
  337. message: message,
  338. orderType: PacificaOrderType.MARKET,
  339. options: { timeout: 1 } // 1ms
  340. };
  341. const response = await signer.signOrder(shortTimeoutRequest);
  342. expect(response.success).toBe(false);
  343. expect(response.error).toContain('TIMEOUT');
  344. });
  345. });
  346. describe('消息大小限制', () => {
  347. test('应该拒绝过大的消息', async () => {
  348. // 创建超过最大大小的消息
  349. const largeMessage = new Uint8Array(PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE + 1);
  350. largeMessage.fill(65); // 填充'A'字符
  351. const request: PacificaSignRequest = {
  352. accountId: testAccountId,
  353. message: largeMessage,
  354. orderType: PacificaOrderType.MARKET
  355. };
  356. const response = await signer.signOrder(request);
  357. expect(response.success).toBe(false);
  358. expect(response.error).toContain('MESSAGE_TOO_LARGE');
  359. });
  360. test('应该接受最大大小以内的消息', async () => {
  361. // 创建恰好最大大小的消息
  362. const maxSizeMessage = new Uint8Array(PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE);
  363. maxSizeMessage.fill(65);
  364. const request: PacificaSignRequest = {
  365. accountId: testAccountId,
  366. message: maxSizeMessage,
  367. orderType: PacificaOrderType.MARKET
  368. };
  369. const response = await signer.signOrder(request);
  370. expect(response.success).toBe(true);
  371. expect(response.signature).toBeDefined();
  372. });
  373. });
  374. describe('错误处理和边界条件', () => {
  375. test('应该处理空消息', async () => {
  376. const emptyMessage = new Uint8Array(0);
  377. const request: PacificaSignRequest = {
  378. accountId: testAccountId,
  379. message: emptyMessage,
  380. orderType: PacificaOrderType.MARKET
  381. };
  382. const response = await signer.signOrder(request);
  383. expect(response.success).toBe(false);
  384. expect(response.error).toContain('INVALID_MESSAGE');
  385. });
  386. test('应该处理无效的订单类型', async () => {
  387. const message = new TextEncoder().encode('test message');
  388. const request: PacificaSignRequest = {
  389. accountId: testAccountId,
  390. message: message,
  391. orderType: 'invalid_order_type' as any
  392. };
  393. const response = await signer.signOrder(request);
  394. expect(response.success).toBe(false);
  395. expect(response.error).toContain('INVALID_ORDER_TYPE');
  396. });
  397. test('应该在并发场景下保持稳定', async () => {
  398. const message = new TextEncoder().encode('concurrent test message');
  399. const concurrentRequests = 20;
  400. const promises = Array.from({ length: concurrentRequests }, (_, index) =>
  401. signer.signOrder({
  402. accountId: testAccountId,
  403. message: message,
  404. orderType: PacificaOrderType.MARKET
  405. })
  406. );
  407. const results = await Promise.all(promises);
  408. results.forEach((result, index) => {
  409. expect(result.success).toBe(true);
  410. expect(result.signature).toBeDefined();
  411. expect(result.executionTime).toBeLessThan(50);
  412. });
  413. // 验证所有签名都是唯一的
  414. const signatures = results.map(r => r.signature);
  415. const uniqueSignatures = new Set(signatures);
  416. expect(uniqueSignatures.size).toBe(signatures.length);
  417. });
  418. });
  419. });